Design tokens
Choose colours by purpose. These swatches use the live shared theme and change with light and dark mode.
Surfaces
Canvas
--color-background-bodySurface
--color-background-surfaceMuted surface
--color-background-mutedPopover
--color-background-popover
Text and borders
Primary text
--color-text-primarySecondary text
--color-text-secondaryDisabled text
--color-text-disabledBorder
--color-borderEmphasized border
--color-border-emphasized
Status
Success
--color-successWarning
--color-warningError
--color-error
Use semantic tokens
.example {background: var(--color-background-surface);color: var(--color-text-primary);border: 1px solid var(--color-border);}
Existing aliases such as --color-bg and --glass-border remain available for compatibility. Use semantic names in new code.
Typography
Suisse Intl gives headings their shape and keeps reading and controls clear; Geist Mono is reserved for code.
Headings · Suisse Intl
A useful idea
How it works
The details
Page, section and item roles. Choose the heading level for the document structure, independently of its visual size.
Reading and controls · Suisse Intl
Good documentation makes the next step clear. Use body text for explanations and supporting text for context that can stay quieter.
Supporting text uses the same family, with less visual emphasis.
Code · Geist Mono
<SiteHeading variant="section">How it works</SiteHeading><SiteText>Your content goes here.</SiteText>
Controls
Interactive examples of the existing UI compatibility API. Native Astryx props are available through @n3wth/ui/primitives.
Button
<Button variant="primary" size="md">Button</Button>
Badge
<Badge variant="default" size="sm">Default</Badge>
Input
<Inputvariant="default"inputSize="md"placeholder="Type something..."/>
Icon (Iconoir)
<Icon name="search" size="md" /><Icon name="github" size="md" />
CodeBlock
import { Nav, Hero, Button, useTheme } from '@n3wth/ui'import '@n3wth/ui/styles'function App() {const { theme, toggleTheme } = useTheme()return (<Navlogo="myapp"items={[{ label: 'Home', href: '/' },{ label: 'About', href: '/about' },]}theme={theme}onThemeToggle={toggleTheme}fixedhideOnScroll/>)}
// Quick startnpm install @n3wth/ui
Compositions
Interactive examples of the existing UI compatibility API. Native Astryx props are available through @n3wth/ui/primitives.
Card
Default Card
Basic border card
Cards contain content and actions about a single subject.
<Card variant="default"><CardHeader><CardTitle>Default Card</CardTitle><CardDescription>Basic border card</CardDescription></CardHeader><CardContent><p>Cards contain content and actions about a single subject.</p></CardContent><CardFooter><Button size="sm" variant="secondary">Action</Button></CardFooter></Card>
Tabs
Overview content with animated indicator that follows the active tab.
<Tabs value={tab} onChange={setTab} variant="underline"><TabsList><TabsTab value="tab1">Overview</TabsTab><TabsTab value="tab2">Features</TabsTab></TabsList><TabsPanel value="tab1">Overview content</TabsPanel><TabsPanel value="tab2">Features content</TabsPanel></Tabs>
Modal
<Modal isOpen={open} onClose={() => setOpen(false)} size="md"><ModalHeader><div><ModalTitle>Modal Title</ModalTitle><ModalDescription>Description text</ModalDescription></div><ModalCloseButton onClick={() => setOpen(false)} /></ModalHeader><ModalBody>Content here</ModalBody><ModalFooter><Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button><Button onClick={() => setOpen(false)}>Confirm</Button></ModalFooter></Modal>
Toast
// Standalone<Toastvariant="success"title="Toast Title"description="Toast description"duration={5000}onDismiss={() => setShow(false)}/>// With useToast hook + Providerconst { toast } = useToast()toast.success({ title: 'Done!', description: 'Action completed' })
NavLink
<NavLink href="/about" variant="underline" isActive>About</NavLink>
CommandBox
npm install @n3wth/ui
<CommandBox command="npm install @n3wth/ui" />
ThemeToggle
const { theme, toggleTheme } = useTheme()<ThemeToggle theme={theme} onToggle={toggleTheme} size="md" />
Site patterns
Page structure belongs to the shared UI layer. The live shell uses these components.
Navigation and footer
import { SiteNavigation, SiteFooter } from '@n3wth/ui/site'<SiteNavigation brand={<a href="/">My site</a>}links={<a href="/work">Work</a>} /><SiteFooter sourceHref="https://github.com/n3wth/n3wth" />
Hero and sections
import { PageHeader, SiteSection, SiteHeading, SiteText } from '@n3wth/ui/site'<PageHeader title="Work" description="Selected projects."actions={<a href="/resume.pdf">Resume (PDF)</a>} /><SiteSection><SiteHeading>Projects</SiteHeading><SiteText>What each project helps people do.</SiteText></SiteSection>
Decorative visual bands
import { AssembleField, VisualBand } from '@n3wth/ui/visuals'import '@n3wth/ui/site.css'<VisualBand height="clamp(190px, 34svh, 340px)"><AssembleField clusters={[[530, 132], [645, 284], [762, 158]]}width={900} height={400} /></VisualBand>
Hooks
React hooks for theme, media queries, accessibility, and animations.
useTheme
import { useTheme } from '@n3wth/ui'function ThemeSwitch() {const { theme, setTheme, toggleTheme } = useTheme()return (<button onClick={toggleTheme}>{theme === 'dark' ? 'Switch to Light' : 'Switch to Dark'}</button>)}
useMediaQuery / useIsMobile / useBreakpoint
Current breakpoint: xs
import { useIsMobile, useBreakpoint, useMediaQuery } from '@n3wth/ui'function ResponsiveLayout() {const isMobile = useIsMobile() // < 768pxconst isTablet = useIsTablet() // 768-1023pxconst isDesktop = useIsDesktop() // >= 1024pxconst breakpoint = useBreakpoint() // 'sm' | 'md' | 'lg' | 'xl' | '2xl'const isWide = useMediaQuery('(min-width: 1440px)')return (<div className={isMobile ? 'stack' : 'grid-cols-3'}>{isWide && <Sidebar />}<Main /></div>)}
useReducedMotion
import { useReducedMotion } from '@n3wth/ui'function AnimatedCard() {const prefersReducedMotion = useReducedMotion()return (<divclassName={prefersReducedMotion ? 'opacity-100' : 'animate-fade-in'}style={{ transition: prefersReducedMotion ? 'none' : 'all 0.3s ease' }}>Accessible animation</div>)}
useCountUp
import { useCountUp } from '@n3wth/ui'function StatsCounter() {const { value, ref } = useCountUp(1000, {duration: 2,onScroll: false,})return <span ref={ref}>{value}</span>}
useKeyboardShortcuts
Register keyboard shortcuts with modifier keys. Handles platform differences (Cmd vs Ctrl) automatically.
import { useKeyboardShortcuts, getModifierKey } from '@n3wth/ui'function SearchDialog() {const [open, setOpen] = useState(false)const modKey = getModifierKey() // 'Cmd' | 'Ctrl'useKeyboardShortcuts([{key: 'k',modifiers: ['meta'],handler: () => setOpen(true),description: 'Open search',},])return <span>Press {modKey}+K to search</span>}
Motion policy
Keep route content visible immediately. Existing animation hooks are compatibility tools for deliberate demonstrations and functional feedback, not a default page treatment.