Building Extensions
Styling & Theming
Customize the appearance of extension UI components within the constraints of your embedding application's design system. Extensions automatically inherit the host application's theme, so you can focus on layout and component selection rather than color or typography 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
Use component props (not CSS) to control visual style:
// 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