Customization
Use customization with the current published Askr packages.
@askrjs/ui0.0.13@askrjs/themes0.0.13
How to use customization
Customization should use the standard themed surface unless the application is deliberately implementing its own design system on top of @askrjs/ui.
- Import the themed component from @askrjs/themes/components; use @askrjs/ui directly only when building a custom visual system.
- Keep customization labels, state, and application actions visible at the call site instead of styling internal DOM nodes.
- 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>Purpose
The customization path is deliberately narrow: reach for a token override first, a public style hook second, and a full component override only as a last resort. That ordering keeps custom styling resilient to internal implementation changes, since tokens and `data-*` hooks are the part of the contract Askr commits to keeping stable.
Install and import
There's no separate install step — customization is plain CSS layered after `@import "@askrjs/themes/default";` in your app's stylesheet. You're writing selectors against the tokens and data attributes the default theme already emits, not importing anything new.
Live examples
A token override looks like `:root { --ak-color-primary: purple; --ak-radius-md: 12px; }` and cascades through every component that consumes those tokens. A targeted style override looks like `:where(.btn-primary, [data-slot="button"][data-variant="primary"]) { background: black; }` — grouping the convenience class alias with the canonical `data-slot` selector in one low-specificity rule.
Anatomy
The stable selector surface is built from canonical attributes — `data-slot`, `data-state`, `data-disabled`, `data-orientation`, `data-variant`, and `data-size` — plus a small set of familiar kebab-case class aliases like `.btn`, `.btn-primary`, `.card`, `.input`, and `.badge-success`. Alias classes exist purely as an authoring convenience; they're documented as "not a replacement source of truth," so any rule using one should also include the matching canonical selector.
State model
Overrides key off the component's real runtime state through `data-state` and `data-disabled`, not through toggling your own classes. Because that state is set by the underlying headless component (or the themed component's own logic when there's no headless counterpart), your CSS stays correct automatically as state changes — you never have to sync a class name to match.
Keyboard and accessibility
Customization should never strip focus-visible treatment; the `--ak-focus-*` tokens control its appearance, so override those tokens rather than removing the underlying `:focus-visible` styling outright. Losing visible focus indicators is one of the easiest ways a customization pass quietly breaks keyboard accessibility.
Styling and tokens
Icon styling follows the same hook pattern as everything else: `[data-slot="icon"][data-size="sm"] { --ak-icon-size-sm: 0.875rem; --ak-icon-stroke-width-sm: 1.5; }` retunes small icons globally without touching component markup. The rule of thumb throughout is: prefer token overrides before component overrides, and prefer overriding a variable over overriding a property directly.
API
There's no JavaScript API for customization specifically — the contract is the selector and token vocabulary itself: `--ak-*` custom properties, canonical `data-*` attribute names, and `:where()` for keeping specificity low so your overrides stay easy to override again later if needed.
Edge cases
Avoid deep selectors that reach into a component's internal DOM structure — they're not part of the contract and can break silently on a minor version bump. Avoid `!important` entirely; the low-specificity baseline exists precisely so you don't need it. And don't treat class aliases as guaranteed long-term API — new aliases are added selectively, not automatically, for every internal slot.
Related pages
See Theme Tokens, Modes, and Direction for the full token catalog these overrides draw from, and Structures for how the Block layout engine's own responsive variables fit into the same override model.