Introduction
346 components built on their own primitives. A CLI copies them into your repo and they become yours — there is no package to upgrade and nothing to fight when a design changes.
Not a dependency
astralyx-ui is a CLI and a registry, not a component library you import from. It writes source files into your project and then gets out of the way — the components in your tree have no link back to it, and upgrading the CLI cannot change a line you are shipping.
Every primitive lives in this repository: the slot that powers asChild, the popper that places every floating layer, the field that delegates focus, the listbox, the tabs, the router. Nothing is imported from a headless-UI library, so nothing can change under you.
That is a trade. You own the accessibility work — and it is done: every component here is checked for ARIA wiring, keyboard paths and focus management on every build.
One style contract
No component spells out its own focus ring, corner radius or control height. They compose fragments from src/lib/styles.ts, which is the single place any of it changes.
export const controlSize = {
xs: 'h-7 gap-1.5 px-3.5 text-xs rounded-full [corner-shape:round]',
sm: 'h-8 gap-1.5 px-3.5 text-sm rounded-[var(--radius-control-sm)]',
md: 'h-9 gap-2 px-4.5 text-sm rounded-[var(--radius-control-md)]',
lg: 'h-10 gap-2 px-6 text-sm rounded-[var(--radius-control-lg)]',
xl: 'h-12 gap-2.5 px-8 text-base rounded-[var(--radius-control-xl)]',
} as const
// Change a rung here and every control on it follows.The rules it holds to
| Rule | Why |
|---|---|
| Colour-only interaction | Nothing moves, resizes or gains elevation on hover or press. Layout never shifts under the pointer. |
| No shadows | Depth comes from a surface ladder — page, card, header, group — not from stacked elevation. |
| Secondary over outline | A screen of outlined controls is a grid of boxes with no hierarchy. A tint separates without another line. |
| iOS-style corners | corner-shape: squircle everywhere, with a circular fallback where it is unsupported. |
| One grid | Heights, radii, icon sizes and type all come from named scales. Off-grid values are caught on every build. |