84 components · server-first · 0 KB static parts

Interfaces with a
stellar finish

A React component library on semantic tokens — one brand color restyles everything at runtime. Try it: this whole section is listening.

#eab308
npx astralis-cli create my-app
scaffolds and wires it up — what the CLI does

Mission control

Recolored by the swatches — no rebuild

Live
+1
Production
Deploys this week1,28418.9% vs last week

Built on tokens, not guesses

Every cell below is live — the same components and tokens you’d ship.

Dark mode built in

Semantic tokens flip with one class on the root. Flip it now:

11 hues, 4 status aliases

One accent channel recolors any component — no per-hue CSS.

Zero build step

Precompiled CSS. No plugins, no config — your bundler just serves a stylesheet.

pnpm add astralis-ui

Responsive props

Breakpoint maps on every style prop — resize the window.

p={{ base: '3', md: '4' }} — this box changes at the md breakpoint.

Static parts ship zero JavaScript

Every static component is a true Server Component — build-gate enforced, labeled on every docs page. The same page in five libraries, and the client JS each adds:

Astralis15.1 kB
shadcn/ui36.0 kB
Radix Themes41.4 kB
MUI58.0 kB
Chakra94.5 kB
Gzipped, over bare Next.js 16.3 and React 19.2, production build. Method and pages (opens in new tab)

Design tokens end to end

Named roles resolve per theme; components never see a hex.

--astralis-color-surface-base
--astralis-color-label-base
--astralis-color-accent-solid
--astralis-color-stroke-subtle

84 components, all real

Nothing below is a screenshot — hover to pause, then go meet them in the docs.

Component docs →
Design
Active
+1
pnpm add astralis-ui
Beta
v0.7.8
Pending
@jo

The code is the demo

Each snippet is the literal source of the preview beside it — the same guarantee every docs page makes.

One invalid flag restyles the field and swaps the message.

"use client";

import { useState } from "react";
import { Field, Input, Switch, VStack } from "astralis-ui";

export function FieldError() {
  const [invalid, setInvalid] = useState(true);

  return (
    <VStack gap="5" alignItems="stretch" w="full" maxW="xs">
      <Switch checked={invalid} onChange={(e) => setInvalid(e.target.checked)} size="sm">
        Simulate a validation error
      </Switch>

      {/* One `invalid` flag restyles the input and swaps the message. */}
      <Field invalid={invalid} required>
        <Field.Label>Username</Field.Label>
        <Input placeholder="astro_naut" />
        {invalid ? (
          <Field.ErrorText>That username is already taken.</Field.ErrorText>
        ) : (
          <Field.HelpText>Letters, numbers and underscores only.</Field.HelpText>
        )}
      </Field>
    </VStack>
  );
}
0Components
0Accent hues
0Live examples
0 KBClient JS in static parts

Ship something stellar

Install the package, wrap your app in the provider, and every component on this site is yours.