Components#
Every component imports from onejs-ui and is styled by the active theme. Controlled inputs follow a value + onChange(value) pattern — onChange receives a plain value (a boolean, number, or string), not an event.
import { Button, Card, Checkbox, Slider /* … */ } from "onejs-ui"Layout#
Card#
A surface container. variant="raised" lifts it above the page with surfaceRaised; variant="surface" (default) sits flush.
<Card variant="raised" style={{ width: 360 }}>
{/* content */}
</Card>Stack, HStack, VStack#
Flex containers with a gap (applied as margins, since UI Toolkit has no gap). HStack/VStack are Stack with direction preset to row/column.
<VStack gap={16}>
<HStack gap={8}>
<Button>Save</Button>
<Button intent="ghost">Cancel</Button>
</HStack>
</VStack>| Prop | Type | Default |
|---|---|---|
direction | "row" \| "column" | "column" |
gap | number (px) | 0 |
align | cross-axis alignment | — |
justify | main-axis alignment | — |
Divider#
A 1px separator line in the border color.
<Divider />
<Divider orientation="vertical" />Spacer#
Empty space inside a flex container. With size it's fixed; without, it flexes to fill.
<HStack>
<Text>Left</Text>
<Spacer />
<Text>Right</Text>
</HStack>Typography#
Text#
Body text with a tone and size scale.
<Text>Default body text</Text>
<Text tone="muted" size="sm">Secondary detail</Text>tone:"default" | "muted" | "subtle"size:"sm" | "md" | "lg" | "xl"
Heading#
Section headings at three levels.
<Heading level={1}>Settings</Heading>
<Heading level={3}>Audio</Heading>level:1 | 2 | 3
Form controls#
Button#
intent sets the visual style; size sets the size step. Content is passed as children.
<Button onClick={save}>Primary</Button>
<Button intent="secondary" onClick={cancel}>Secondary</Button>
<Button intent="ghost" size="sm">Ghost</Button>
<Button intent="danger" onClick={remove}>Delete</Button>intent:"primary" | "secondary" | "ghost" | "danger"(default"primary")size:"sm" | "md" | "lg"(default"md")onClick:(e) => void
Checkbox#
A labeled checkbox on the native UI Toolkit toggle.
const [agree, setAgree] = useState(false)
<Checkbox label="I agree" value={agree} onChange={setAgree} />label:stringvalue:boolean·onChange:(checked: boolean) => void
Switch#
A toggle switch; the label renders to the left.
const [on, setOn] = useState(true)
<Switch label="Notifications" value={on} onChange={setOn} />value:boolean·onChange:(checked: boolean) => void
Input#
A text field on the native UI Toolkit TextField — a proper focus target with full keyboard/IME behavior.
const [name, setName] = useState("")
<Input value={name} onChange={setName} />value:string·onChange:(value: string) => void- Other
TextFieldprops (e.g. placeholder) pass through.
Slider#
A slider on the native UI Toolkit Slider, with pointer drag and keyboard steps.
const [vol, setVol] = useState(60)
<Slider value={vol} lowValue={0} highValue={100} onChange={setVol} />value:number·onChange:(value: number) => voidlowValue/highValue: range bounds.
RadioGroup#
A single-choice group. value is the selected index (-1 for none).
const [plan, setPlan] = useState(1)
<RadioGroup value={plan} choices={["Free", "Pro", "Team"]} onChange={setPlan} />choices:string[]value:number(index,-1= none) ·onChange:(index: number) => void
Select#
A dropdown of options. value is the selected option's value string.
const [fruit, setFruit] = useState("apple")
<Select
value={fruit}
options={[
{ label: "Apple", value: "apple" },
{ label: "Orange", value: "orange" },
]}
onChange={setFruit}
/>options:{ label: string; value: string }[]value:string·onChange:(value: string) => void
Feedback#
Badge#
A small status pill.
<Badge intent="success">Active</Badge>
<Badge intent="danger">Error</Badge>intent:"neutral" | "primary" | "success" | "warning" | "danger"
Toast#
Transient notifications. Wrap your app in <ToastProvider> once, then call useToast() (which returns a toast function) from anywhere.
import { ToastProvider, useToast } from "onejs-ui"
function SaveButton() {
const toast = useToast()
return (
<Button onClick={() => toast({ message: "Saved", tone: "success" })}>
Save
</Button>
)
}
// at the root:
<ToastProvider placement="bottom-right">
<App />
</ToastProvider>toast(options)—{ message, title?, tone?, duration? }tone:"default" | "success" | "warning" | "danger" | "info"duration: ms before auto-dismiss;0keeps it open. Default4000.
Overlays#
All overlays render into a portal and share positioning, dismissal, and motion. placement accepts sides and alignments like "bottom-start" or "top".
Tooltip#
A label shown on hover/focus of its child.
<Tooltip label="Delete permanently">
<Button intent="danger">Delete</Button>
</Tooltip>Popover#
A floating panel anchored to a trigger. Uncontrolled by default; pass open + onOpenChange to control it.
<Popover trigger={<Button>Options</Button>} placement="bottom">
<Text>Popover content</Text>
</Popover>DropdownMenu#
A menu of actions anchored to a trigger.
import { DropdownMenu, MenuItem, MenuSeparator } from "onejs-ui"
<DropdownMenu trigger={<Button>Actions</Button>}>
<MenuItem onSelect={duplicate}>Duplicate</MenuItem>
<MenuItem onSelect={rename}>Rename</MenuItem>
<MenuSeparator />
<MenuItem danger onSelect={remove}>Delete</MenuItem>
</DropdownMenu>MenuItem: onSelect, disabled, danger. The menu closes after a selection.
Dialog#
A centered modal with a backdrop and a focus trap. Controlled via open / onClose.
const [open, setOpen] = useState(false)
<Dialog open={open} onClose={() => setOpen(false)} title="Delete file?">
<Text tone="muted">This can't be undone.</Text>
<HStack gap={8}>
<Button intent="ghost" onClick={() => setOpen(false)}>Cancel</Button>
<Button intent="danger" onClick={confirm}>Delete</Button>
</HStack>
</Dialog>open:boolean·onClose:() => voidtitle,dismissOnEscape(defaulttrue), backdrop-dismiss (defaulttrue).
Drawer#
A panel that slides in from an edge. Same control model as Dialog.
const [open, setOpen] = useState(false)
<Drawer open={open} onClose={() => setOpen(false)} side="right" title="Filters">
{/* content */}
</Drawer>side:"left" | "right" | "top" | "bottom"(default"right")open,onClose,title,dismissOnEscape.