Building Extensions
Styling & Theming
Extensions inherit the embedding application's theme automatically. The SDK component library (ui.* namespace) renders inside the surrounding application's styling context, so colors, fonts, and spacing match without any configuration.
Theme Inheritance
The ui.* components automatically use the embedding application's design tokens:
- Colors — text, backgrounds, borders adapt to the application's color scheme
- Typography — font family, sizes, and weights match the application
- Spacing — padding and margins follow the application's spacing scale
- Dark mode — components respond to the application's light/dark mode setting
No CSS or theme configuration is needed in the extension.
The className Prop
Most ui.* components accept a className prop for layout adjustments:
<ui.Card className="mt-4">
<ui.CardContent className="p-6">
<ui.Text className="text-center">Centered text</ui.Text>
</ui.CardContent>
</ui.Card>
Use className for:
- Layout (margin, padding, flexbox, grid)
- Positioning (relative, absolute)
- Sizing (width, height, max-width)
- Spacing between elements
Avoid overriding with className:
- Colors and backgrounds (breaks theme consistency)
- Font families and sizes (breaks typography scale)
- Border styles (use component variants instead)
Layout Components
Use the built-in layout components instead of raw CSS:
| Component | Purpose |
|---|---|
<ui.Stack> | Vertical layout with consistent spacing |
<ui.Inline> | Horizontal layout with consistent spacing |
<ui.Separator> | Visual divider between sections |
<ui.ScrollArea> | Scrollable container for overflow content |
<ui.Stack className="gap-4">
<ui.Heading level={3}>Section Title</ui.Heading>
<ui.Text>Section content</ui.Text>
<ui.Separator />
<ui.Inline className="gap-2">
<ui.Button variant="primary">Save</ui.Button>
<ui.Button variant="ghost">Cancel</ui.Button>
</ui.Inline>
</ui.Stack>
Component Variants
Control visual style using component props rather than CSS:
// Buttons — variant controls appearance
<ui.Button variant="primary">Primary action</ui.Button>
<ui.Button variant="ghost">Secondary action</ui.Button>
// Badges — variant + hue + tone for semantic colors
<ui.Badge variant="default" hue="blue" tone="strong">Active</ui.Badge>
<ui.Badge variant="default" hue="red" tone="subtle">Error</ui.Badge>
// Text — tone for semantic meaning
<ui.Text tone="subdued">Helper text</ui.Text>
<ui.Text tone="critical">Error message</ui.Text>
CSS Constraints
Extensions run in a sandboxed iframe. These constraints apply:
- No global CSS — styles don't leak between extensions or into the embedding application
- No
documentaccess — cannot inject stylesheets or modify the DOM directly - No
window.location— cannot read or modify the URL - Component-only styling — use
classNameonui.*components, not raw HTML elements - Bundle size limit — keep CSS dependencies minimal (under 500KB total bundle)
Responsive Design
Extensions render in a constrained viewport (the embedding application's sidebar or panel). Design for narrow widths:
// Use ScrollArea for content that may overflow
<ui.ScrollArea className="h-[400px]">
<ui.Stack className="gap-3">
{items.map((item) => (
<ItemCard key={item.id} item={item} />
))}
</ui.Stack>
</ui.ScrollArea>
- Assume a narrow viewport (~300-400px wide)
- Use
<ui.ScrollArea>for long lists or content - Avoid horizontal scrolling — stack elements vertically
- Test at the minimum panel width the embedding application supports