Core UI components, theme system, and utilities for the XDS design system. For project setup, see Quick Start below.
Look up any component's full API (props, types, best practices, and theming):
node node_modules/@astryxdesign/core/docs.mjs Button # full docs for a component
node node_modules/@astryxdesign/core/docs.mjs --list # list all components
node node_modules/@astryxdesign/core/docs.mjs --list --brief # brief summariesBuilding a full page? Start with a template rather than composing from scratch.
Templates are content-only; they compose XDSLayout with header, content, and
panel slots into common page patterns (dashboards, settings, forms, detail pages).
Wrap them in your own app chrome (XDSAppShell, XDSTopNav, XDSSideNav) to add
global navigation.
Requires @astryxdesign/cli (npm install -D @astryxdesign/cli):
npx astryx template --list # browse all page and block templates
npx astryx template dashboard # emit full page source
npx astryx template settings --skeleton # layout skeleton with spatial annotationsThe CLI (@astryxdesign/cli) provides additional tooling:
npx astryx --help # full listing of all commands
npx astryx component Button # full docs + related block templates
npx astryx docs # reference docs (principles, tokens, theming, styling)
npx astryx docs theme # theming guide (Theme, defineTheme, light/dark)
npx astryx docs tokens # spacing, color, radius, typography token reference
npx astryx init # initialize XDS in your project
npx astryx theme build # build theme CSS for production
npx astryx swizzle Button # eject component source for customization
npx astryx upgrade --apply # run codemods to migrate between versions
npx astryx discover # discover external XDS packages
npx astryx gap-report # report a missing capability| Package | Description |
|---|---|
@astryxdesign/cli |
CLI tooling: component docs, templates, scaffolding, codemods |
@astryxdesign/theme-neutral |
Muted, minimal theme (Lucide icons) |
Install XDS and a theme:
npm install @astryxdesign/core @astryxdesign/theme-neutralThen pick your setup below based on your framework and styling approach.
The fastest way to get started. No build plugins, no PostCSS, no Babel config — Astryx ships pre-built CSS and JS, so you import three stylesheets (order matters) and wrap your app in a theme provider.
src/app/globals.css
@import '@astryxdesign/core/reset.css';
@import '@astryxdesign/core/astryx.css';
@import '@astryxdesign/theme-neutral/theme.css';The import order maps to the layer cascade: reset.css (@layer reset) → astryx.css component styles (@layer astryx-base) → theme.css token overrides (@layer astryx-theme).
src/app/providers.tsx
'use client';
import Link from 'next/link';
import {Theme} from '@astryxdesign/core/theme';
import {LinkProvider} from '@astryxdesign/core/Link';
import {neutralTheme} from '@astryxdesign/theme-neutral/built';
export function Providers({children}: {children: React.ReactNode}) {
return (
<Theme theme={neutralTheme}>
<LinkProvider component={Link}>{children}</LinkProvider>
</Theme>
);
}src/app/layout.tsx
import './globals.css';
import {Providers} from './providers';
export default function RootLayout({children}: {children: React.ReactNode}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}No build plugins needed; XDS ships pre-built CSS that works alongside Tailwind.
src/app/globals.css
@layer reset, theme, base, astryx-base, astryx-theme, components, utilities;
@import 'tailwindcss/theme.css' layer(theme);
@import 'tailwindcss/preflight.css' layer(base);
@import '@astryxdesign/core/reset.css';
@import '@astryxdesign/core/astryx.css';
@import '@astryxdesign/theme-neutral/theme.css';
@import '@astryxdesign/core/tailwind-theme.css';
@import 'tailwindcss/utilities.css' layer(utilities);The tailwind-theme.css import maps system tokens to Tailwind utilities via @theme inline:
// Without the bridge — verbose:
<div className="rounded-[var(--radius-container)] bg-[var(--color-background-surface)] text-[var(--color-text-primary)]">
// With the bridge — just works:
<div className="rounded-lg bg-surface text-primary">Some useful mappings:
| Tailwind class | XDS token |
|---|---|
text-primary / text-secondary |
--color-text-primary / --color-text-secondary |
bg-surface / bg-card / bg-body |
--color-background-surface / card / body |
border-border / border-strong |
--color-border / --color-border-emphasized |
bg-success / text-error / text-warning |
Status tokens |
bg-blue-subtle / border-blue-ring / text-blue-vivid |
Hue palette (×10 hues) |
rounded-sm / rounded-md / rounded-lg |
--radius-inner / element / container |
shadow-sm / shadow-md / shadow-lg |
--shadow-low / med / high |
Spacing references var(--spacing-1) as the base unit, so p-4 = 16px, matching XDS's --spacing-4. Arbitrary values still work as an escape hatch: bg-[var(--color-background-surface)].
src/app/providers.tsx
'use client';
import Link from 'next/link';
import {Theme} from '@astryxdesign/core/theme';
import {LinkProvider} from '@astryxdesign/core/Link';
import {neutralTheme} from '@astryxdesign/theme-neutral/built';
export function Providers({children}: {children: React.ReactNode}) {
return (
<Theme theme={neutralTheme}>
<LinkProvider component={Link}>{children}</LinkProvider>
</Theme>
);
}src/app/layout.tsx
import './globals.css';
import {Providers} from './providers';
export default function RootLayout({children}: {children: React.ReactNode}) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}That's it. Start using components:
import {Button} from '@astryxdesign/core/Button';
export default function Page() {
return <Button label="Hello XDS" variant="primary" />;
}Use the pre-built dist alongside StyleX for your own styles.
npm install @astryxdesign/core @astryxdesign/theme-neutralsrc/app/globals.css
@import '@astryxdesign/core/reset.css';
@import '@astryxdesign/core/astryx.css';
@import '@astryxdesign/theme-neutral/theme.css';Providers and layout are the same as the Tailwind example (use @astryxdesign/theme-neutral/built).
npm install @astryxdesign/core @astryxdesign/theme-neutralSame CSS imports and providers as above. No build plugins needed; XDS ships pre-built.
For prototypes, embeds, or pages without a bundler, load the components straight from a public CDN. Two delivery options ship in the published package:
1. UMD global (<script> tag). A single pre-bundled file exposes every export
on window.Astryx. React and ReactDOM are peer dependencies — load them yourself.
Pair it with the precompiled stylesheet.
<!doctype html>
<html data-astryx-theme="neutral">
<head>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@astryxdesign/core/src/reset.css" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@astryxdesign/core/dist/astryx.css" />
</head>
<body>
<div id="root"></div>
<script
crossorigin
src="https://unpkg.com/react@19/umd/react.production.min.js"></script>
<script
crossorigin
src="https://unpkg.com/react-dom@19/umd/react-dom.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@astryxdesign/core/dist/astryx.umd.js"></script>
<script>
const {Button, Card} = window.Astryx;
const e = React.createElement;
ReactDOM.createRoot(document.getElementById('root')).render(
e(Card, null, e(Button, {variant: 'primary'}, 'Hello from a CDN')),
);
</script>
</body>
</html>2. ES modules (no UMD, no globals). Use esm.sh, which rewrites bare imports to browser-resolvable URLs. An import map keeps a single React instance.
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@astryxdesign/core/dist/astryx.css" />
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@19",
"react-dom/client": "https://esm.sh/react-dom@19/client",
"@astryxdesign/core": "https://esm.sh/@astryxdesign/core?external=react,react-dom"
}
}
</script>
<script type="module">
import {createRoot} from 'react-dom/client';
import {Button} from '@astryxdesign/core';
// ...render as usual
</script>Pin a version in production (e.g.
@astryxdesign/core@0.1.1) — unversioned CDN URLs resolve to the latest release and are cached aggressively. The raw ESM entry (dist/index.js) uses barereactimports and will not run from a plain<script src>; use the UMD global or esm.sh as shown above.