Interfaces with a
stellar finish

Accessible, themeable React components for crafting polished web apps and design systems. Server-first, built for the Next.js RSC

#eab308
npx astralis-cli create my-app
Scaffold your React project · How the CLI works

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, with 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, enforced at build time and 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 meet them in the docs.

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

The code is the demo

Each snippet is the exact source of the preview beside it, as on every docs page.

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>
  );
}

More than components

Everything around the library helps you go from idea to shipped page faster.

0Components
0Accent hues
0Live examples
0 KBClient JS in static parts

Ship something stellar

Install the package, add the provider, and every component here is yours.