O!Vector

Components

All components use exclusively semantic token CSS variables. Zero hardcoded values.

Button

Variants
Sizes
States
When to use
  • Primary — single, most important CTA per view
  • Secondary — supporting actions
  • Ghost — low-emphasis, tertiary actions
  • Danger — destructive, irreversible actions
  • ❌ Do not use multiple Primary buttons on the same page
jsx
import { Button } from '@/components/ui/Button'; // Variants <Button variant="primary">Save</Button> <Button variant="secondary">Cancel</Button> <Button variant="ghost">Learn more</Button> <Button variant="danger">Delete</Button> // Sizes <Button size="sm" /> <Button size="md" /> <Button size="lg" /> // States <Button isLoading>Saving…</Button> <Button disabled>Disabled</Button> <Button isIcon variant="secondary"><Settings /></Button>
PropTypeDefaultDescription
variant"primary" | "secondary" | "ghost" | "danger""primary"Visual style
size"sm" | "md" | "lg" | "icon""md"Dimensions
isLoadingbooleanfalseShows spinner, disables interaction
isIconbooleanfalseSquare aspect ratio for icon-only buttons
disabledbooleanfalseDisables the button

Badge

Variants
DefaultPrimarySuccessWarningErrorInfo
jsx
import { Badge } from '@/components/ui/Badge'; <Badge variant="default">Default</Badge> <Badge variant="success">Active</Badge> <Badge variant="error">Failed</Badge> <Badge variant="warning">Pending</Badge> <Badge variant="info">New</Badge>

Input & Select

States
Select
jsx
import { Input, Select } from '@/components/ui/Input'; <Input placeholder="Type here…" /> <Input isSearch placeholder="Search…" /> <Input state="error" placeholder="Error" /> <Input state="success" placeholder="Valid" /> <Select options={[{ label: 'A', value: 'a' }]} />
PropTypeDefaultDescription
state"default" | "error" | "success""default"Validation state with icon
isSearchbooleanfalseAdds search icon prefix

Form Controls

Checkbox
Radio
Switch
jsx
import { Checkbox } from '@/components/ui/Checkbox'; import { Radio } from '@/components/ui/Radio'; import { Switch } from '@/components/ui/Switch'; <Checkbox checked={val} onChange={e => setVal(e.target.checked)} /> <Radio name="group" value="a" checked={val === 'a'} onChange={() => setVal('a')} /> <Switch checked={enabled} onChange={e => setEnabled(e.target.checked)} />

Alerts & Feedback

Loading states
jsx
import { Alert } from '@/components/ui/Alert'; import { Spinner } from '@/components/ui/Spinner'; import { Skeleton } from '@/components/ui/Skeleton'; <Alert variant="success" title="Saved">Changes saved.</Alert> <Alert variant="error" title="Error">Build failed.</Alert> <Alert variant="warning" title="Warning">Expiring soon.</Alert> <Alert variant="info" title="Info">Under review.</Alert> <Spinner size="md" /> <Skeleton className="h-4 w-full" />

Overlays

Dropdown
Tooltip
This is a tooltip
Bottom tooltip
Modal
jsx
import { Dropdown } from '@/components/ui/Dropdown'; import { Tooltip } from '@/components/ui/Tooltip'; import { Modal } from '@/components/ui/Modal'; <Dropdown items={[{ label: 'Edit', value: 'edit' }]} /> <Tooltip content="Help text" position="top"> <Button>Hover me</Button> </Tooltip> <Modal isOpen={open} onClose={close} title="Title" actions={<><Button>Cancel</Button><Button variant="primary">OK</Button></>} > <p>Modal content</p> </Modal>

Tabs

Tab content renders below the tab strip.

jsx
import { Tabs } from '@/components/ui/Tabs'; <Tabs tabs={[ { id: 'overview', label: 'Overview' }, { id: 'api', label: 'API' }, ]} defaultTab="overview" onChange={(id) => console.log(id)} />

Cards

Default Card
Standard card for containing grouped content.
Interactive Card
Hover to see the border and background lift.
jsx
import { Card, CardHeader, CardContent, CardFooter } from '@/components/ui/Card'; <Card variant="default"> <CardHeader>Title</CardHeader> <CardContent>Body content</CardContent> <CardFooter> <Button size="sm">Action</Button> </CardFooter> </Card> <Card variant="interactive"> <CardContent>Hover me</CardContent> </Card>

Table

NameRoleStatusJoined
Amir KarimovAdminActive2024-01
Zarina LeeDesignerActive2024-03
Ivan PetrovDeveloperPending2025-11
jsx
import { Table } from '@/components/ui/Table'; <Table columns={[ { header: 'Name', accessorKey: 'name' }, { header: 'Status', cell: (row) => <Badge>{row.status}</Badge> }, ]} data={[{ name: 'Alice', status: 'Active' }]} />