AstralUI v0.1.9 · docs Home Playground npm GitHub

Documentation

This page is built with @astralui/core - every preview below is the real, shipped component. Use the toggle (top-right) to flip light/dark and watch it all respond.

▶ Open the live playground - the real React components, loaded from npm, fully interactive.

Install & setup

Add the package and its peers, import the stylesheet once, then wrap your app.

pnpm add @astralui/core react react-dom @tabler/icons-react
import '@astralui/core/styles.css';
import { ColorSchemeProvider, AstralThemeProvider, AstralToaster } from '@astralui/core';

function Root() {
  return (
    <ColorSchemeProvider defaultScheme="dark">
      <AstralThemeProvider>
        <AstralToaster />
        <App />
      </AstralThemeProvider>
    </ColorSchemeProvider>
  );
}

Color scheme

The provider persists the scheme and sets data-astral-scheme + color-scheme on <html>. The button below calls the same logic the hook exposes.

const { colorScheme, toggle } = useColorScheme();
<button onClick={toggle}>{colorScheme}</button>

Per-brand theming

Pass a brand color and AstralUI builds a 10-shade palette via generateColors(). Try recoloring this whole page:

<AstralThemeProvider colors={{ primary_color: '#0d9488' }}>
  <App />
</AstralThemeProvider>

// live, unsaved preview (e.g. a brand-color editor):
const { setPreview } = useThemePreview();
setPreview({ primary_color: '#e8590c' });

// buildOrgCss(colors) returns the raw <style> text if you need to inject it yourself (SSR)

Beyond the brand palette, the token layer exposes semantic vars you can use in your own CSS: --au-text, --au-dim, --au-line, --au-surface-2, --au-brand, --au-green / --au-amber / --au-red / --au-blue, and --au-accent (a warm-orange secondary accent), plus the raw --astral-color-* palette. All are theme-aware via light-dark().

Buttons

<button className="au-btn primary">Primary</button>
<button className="au-btn danger">Delete</button>

Inputs

Email
<div className="au-field-label">Email</div>
<div className="au-input"><input /></div>
<textarea className="au-textarea" />

Select

Single-select combobox (searchable / clearable / creatable), portalled above modals.

<AstralSelect value={v} onChange={setV} searchable clearable
  options={[{ value: 'us', label: 'United States' }]} />
<AstralMenu items={[
  { label: 'Edit', onClick: edit },
  { label: 'Delete', danger: true, onClick: remove },
]} />
<AstralModal opened={open} onClose={close} title="Edit profile" width={460}>
  ...
</AstralModal>

// AstralDrawer: same props, slides in from the right
<AstralDrawer opened={open} onClose={close} title="Filters" width={440}>
  ...
</AstralDrawer>

ConfirmModal

<ConfirmModal opened={open} onClose={close} onConfirm={remove}
  title="Delete campaign?" message="This cannot be undone."
  confirmLabel="Delete" danger />

PinInput

<AstralPinInput length={6} value={code} onChange={setCode} />

Notifications

notifications.show({ message: 'Saved', color: 'green' });
const id = notifications.show({ message: 'Working...', loading: true, autoClose: false });
notifications.update({ id, message: 'Done', color: 'green', loading: false, autoClose: 2000 });

DateInput

<DateInput type="date" value={date} onChange={setDate} />

// helpers: Date -> input string (local), e.g. for min/max or defaults
dateToInputStr(date);      // "2026-06-06"
dateTimeToInputStr(date);  // "2026-06-06T14:30"

StatusBadge

Running Paused Failed Idle
<StatusBadge status="running" label="Running" />
<StatusBadge status="custom" label="Paused" color="#eab308" />

Avatar

AB JD
<Avatar name="Ada Byron" url={pictureUrl} size={44} />
<Avatar name="Jane Doe" radius={14} />  // initials fallback

A clearable search field. The demo below filters the list live as you type - in real use you'd debounce the value in the parent before querying an API.

  • AstralModal
  • AstralSelect
  • ConfirmModal
  • Donut
  • Sparkline
  • StatusBadge
  • Avatar
  • SearchInput
const [q, setQ] = useState('');
<SearchInput value={q} onChange={setQ} placeholder="Search components..." />

// debounce in the parent when querying an API:
useEffect(() => {
  const t = setTimeout(() => runQuery(q), 300);
  return () => clearTimeout(t);
}, [q]);

Collapsible

A folding panel whose content animates in and out - the region transitions an exact measured max-height (grid 0fr/1fr snaps shut on collapse in some browsers) and the chevron rotates. Uncontrolled via defaultOpen, or controlled via open / onOpenChange.

Connections sent
1,284
Accepted
612
Replied
233
const [open, setOpen] = useState(false);

// uncontrolled
<Collapsible title="Connection funnel">
  <FunnelBars data={funnel} />
</Collapsible>

// controlled
<Collapsible open={open} onOpenChange={setOpen} title="Details">…</Collapsible>

Spinner

<Spinner size={24} />

Sparkline & Delta

▲ 11% ▼ 4%
<Sparkline points={[3,5,4,8,7,11]} color="violet.6" />
<Delta current={420} previous={377} />

// chartColor() resolves "hue.shade" -> var(--astral-color-...); hex/var pass through
chartColor('violet.6'); // "var(--astral-color-violet-6)"

Donut, Funnel & Stacked bars

Hover a slice, bar, or legend item - the highlight is native to the component (linked hover, others dim).

1,284sent
412Accepted
872Pending
Sent
1,284
Accepted
792
Replied
412
Connects
Replies
Mon
12054
Tue
9840
Wed
14072
<Donut centerValue="1,284" centerLabel="sent" data={[
  { name: 'Accepted', value: 412, color: 'green.6' },
  { name: 'Pending', value: 872, color: 'violet.6' },
]} />
<FunnelBars data={[{ stage: 'Sent', value: 1284, color: 'violet.6' }]} />
<StackedBars series={[...]} rows={[...]} />

Auth shell

Centered sign-in / sign-up layout. Build the form with the au-auth-* classes.

Welcome back

No account? Sign up
<AuthShell backdrop="space">
  <AuthCard banner={<Logo />}>
    <h1 className="au-auth-title">Welcome back</h1>
    <form className="au-auth-form">
      <div className="au-auth-field"><label>Email</label>
        <div className="au-auth-input"><input /></div></div>
      <button className="au-auth-btn primary block">Sign in</button>
    </form>
  </AuthCard>
</AuthShell>

Backgrounds

<SpaceBackground fixed />
<GridBackground>...</GridBackground>