Extension guides
Shared UI
Import host-provided components so graphical extensions match NativePi's density, interaction states, and active surface without bundling a second component system.
Import components
import {
Badge,
Button,
Dialog,
DialogContent,
DialogDescription,
DialogTitle,
DialogTrigger,
} from "@nativepi/extension-api/ui";These components resolve only inside NativePi. Importing them in the Pi entry or rendering them in a standalone browser throws an explicit host error.
Component groups
| Group | Exports |
|---|---|
| Actions | Button, Badge |
| Inputs | Input, Textarea, Label, Switch, Separator |
| Fields | Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel |
| Dialogs | Dialog, DialogTrigger, DialogClose, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription |
| Menus | Menu, MenuTrigger, MenuContent, MenuGroup, MenuLabel, MenuItem, MenuSeparator |
| Selects | Select, SelectTrigger, SelectValue, SelectContent, SelectGroup, SelectLabel, SelectItem, SelectSeparator |
Buttons and badges
Button variants are default, secondary, destructive, outline, ghost, and link. Sizes are default, xs, sm, lg, xl, and matching icon sizes. Badge supports the same variants.
Dialogs and menus
<Dialog>
<DialogTrigger render={<Button variant="outline">Open details</Button>} />
<DialogContent>
<DialogHeader>
<DialogTitle>Query details</DialogTitle>
<DialogDescription>Review the query before running it.</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose render={<Button variant="ghost">Cancel</Button>} />
<Button>Run query</Button>
</DialogFooter>
</DialogContent>
</Dialog>Triggers follow Base UI composition. Pass an element through render; do not use Radix's asChild pattern. Menu and select content accept side, alignment, and offset props for placement.
Menu example
<Menu>
<MenuTrigger render={<Button size="sm" variant="ghost">Actions</Button>} />
<MenuContent align="end">
<MenuLabel>Result actions</MenuLabel>
<MenuItem onClick={() => void context.actions.copyText(result)}>Copy result</MenuItem>
<MenuSeparator />
<MenuItem variant="destructive" onClick={clearResult}>Clear result</MenuItem>
</MenuContent>
</Menu>Settings rows
SettingsActionRow: label, optional description, and custom child actionSettingsSwitchRow: boolean value withonChangeSettingsSelectRow: string value, options, andonChangeSettingsTextRow: text or multiline value committed throughonCommitSettingsSliderRow: bounded numeric value, step, formatter, andonChange
<SettingsSwitchRow
label="Confirm destructive queries"
description="Ask before running DELETE, DROP, or TRUNCATE."
checked={settings.confirmDestructive}
onChange={(checked) => void updateSettings({ confirmDestructive: checked })}
/>Extension-specific styling
NativePi's Tailwind build runs before renderer source is compiled, so package-specific utility classes do not generate CSS. Use inline styles for small layouts and semantic variables for color:
var(--foreground)var(--muted-foreground)var(--border)var(--destructive)var(--warning)var(--success)
<div
style={{
display: "grid",
gap: 8,
color: "var(--foreground)",
borderBlockEnd: "1px solid var(--border)",
}}
>
{children}
</div>Icons
Use Phosphor icons to match NativePi. Mark an icon inside a button with data-icon="inline-start" or data-icon="inline-end" so spacing follows the button component.
Type reference
Exact prop interfaces are listed in the API reference and exported from @nativepi/extension-api/ui for editor completion.