Askr
UI & Components

UI and Components

Compose headless behavior with theme-owned appearance, accessible structures, and explicit state.

  • @askrjs/ui0.0.13
  • @askrjs/themes0.0.13

How to use ui and components

UI and Components should use the standard themed surface unless the application is deliberately implementing its own design system on top of @askrjs/ui.

  1. Import the themed component from @askrjs/themes/components; use @askrjs/ui directly only when building a custom visual system.
  2. Keep ui and components labels, state, and application actions visible at the call site instead of styling internal DOM nodes.
  3. Verify keyboard behavior, focus movement or return, disabled state, and both standard themes.
import { Button, ThemeScope, ThemeToggle } from '@askrjs/themes/components';

<ThemeScope defaultTheme="system" storageKey="app-theme">
  <Button>Save project</Button>
  <ThemeToggle aria-label="Change color theme" />
</ThemeScope>

Headless and themed layers

Askr's component system is split into two packages that ship separately: @askrjs/ui, which owns interaction behavior, focus handling, and ARIA wiring with no visual opinion at all, and @askrjs/themes, which owns the default look, CSS tokens, and a styled component catalog built on top of it. When a headless primitive exists — Button, Dialog, Select, and similar — the themed version literally imports and wraps it rather than reimplementing behavior, so keyboard handling and state management stay in one place. Reach for @askrjs/ui directly when you're writing your own design system from scratch, or @askrjs/themes when you want a shipped, styled result.

Package boundaries

The split follows a simple rule from the themes package's own docs: @askrjs/askr owns what exists and when, @askrjs/ui owns behavior, state, focus, and ARIA coordination, and @askrjs/themes owns visual-only components plus Block-first structural presets. Concretely, Button ships from @askrjs/ui and @askrjs/themes re-exports and styles it, while ButtonGroup, Close, Field, and InputGroup live only in themes because they're pure visual composition wrappers with no independent behavior to headless-ify. Knowing which package owns a given piece tells you where to look when something needs fixing — behavior bugs live upstream in @askrjs/ui, visual bugs live in @askrjs/themes.

Component page contract

Every component page in this section follows the same shape — purpose, install and import, live examples, anatomy, state model, keyboard and accessibility, styling and tokens, an API reference grounded in the real prop types, edge cases, and related pages — so once you've read one you know how to navigate the rest. Pages link out to the specific @askrjs/ui and @askrjs/themes subpath exports they cover rather than the package roots, which keeps import statements copy-pasteable. If a page has no @askrjs/ui subpath listed, that's not an oversight: it means the component genuinely has no headless counterpart and ships only as a themed component.

Experimental families

A handful of component families are marked experimental — Combobox and Command, Calendar and Date Picker, Native Select and Input OTP, and Drawer and Sheet — and all four share the same reason: none of them has an @askrjs/ui headless primitive backing them. They exist only in @askrjs/themes today, which means their behavior and markup are more likely to change shape as a headless version gets built out. Treat their APIs as less stable than the rest of the catalog and expect follow-up releases to adjust them.