@astryx-svelte/core
Svelte 5 components for Astryx, Meta's open source design system.Styles: import a stylesheet, or compile it yourself
Components are styled with StyleX, and there are two ways to get their CSS.
Pick one.
1. Import the pre-built stylesheet — no bundler configuration at all
The same thing Astryx's own package does, and what most projects should do:
tsimport '@astryx-svelte/core/base.css';import '@astryx-svelte/core/astryx.css';import '@astryx-svelte/theme-neutral/theme.css';
That is the entire setup.
dist ships compiled, so nothing needs to run StyleX.astryx.css carries every component's styles — 131 kB, one @layer astryx-base, checked against
@astryx-svelte/core's published stylesheet on every test run: 1,463 shared atomic classes, zero
differing rules. The cost is that you ship every component's CSS whether you use it or not.2. Compile it yourself, from source
Every subpath also publishes a
source condition pointing at the TypeScript. Ask your bundler for
it and compile the package yourself, and you emit only the atomic classes your app actually reaches
— smaller than the whole stylesheet, at the cost of configuration:ts// vite.config.ts — alongside the preset belowexport default defineConfig({plugins: [astryx(), sveltekit()],resolve: { conditions: ['source'] }});
This is also the property that makes the port verifiable: the compiler derives class names from the
source, so authoring against Astryx's token references emits byte-identical atomic CSS.
Getting this route wrong fails without an error: the components render, and they render
unstyled. If that happens, run
pnpm exec astryx-svelte doctor — it accepts either route, and names
whichever piece is missing.For Vite (and therefore SvelteKit), use the preset:
ts// vite.config.tsimport { astryx } from '@astryx-svelte/core/vite';import { sveltekit } from '@sveltejs/kit/vite';import { defineConfig } from 'vite';export default defineConfig({plugins: [astryx(), sveltekit()]});
That is the whole setup.
astryx() takes include (further packages that ship uncompiled
.stylex.js), rootDir (the StyleX module-resolution root — a monorepo importing .stylex
modules across packages wants the workspace root, not the default process.cwd()), and dev.<details>
<summary>What the preset does, and why it is three things rather than one</summary>
The plugin compiles the styles. The other two exist because Vite has two separate ways to route a
dependency around its own plugin pipeline, and each defeats the compiler on its own:
tsexport default defineConfig({plugins: [stylex({dev: process.env.NODE_ENV !== 'production',runtimeInjection: false,treeshakeCompensation: true,useCSSLayers: true,// Without explicit targets, lightningcss lowers `light-dark()` to a pair of// `var(--lightningcss-*)` references that resolve to nothing, and every// colour token silently goes empty.lightningcssOptions: {targets: { chrome: 123 << 16, firefox: 120 << 16, safari: (17 << 16) | (5 << 8) }},unstable_moduleResolution: { type: 'commonJS', rootDir: import.meta.dirname }}),sveltekit()],// Vite's dev-time pre-bundler runs esbuild outside the plugin pipeline, so anything// it optimises never reaches the StyleX transform and `stylex.create` survives into// the browser as a runtime no-op.optimizeDeps: { exclude: ['@astryx-svelte/core'] },// Same reasoning for the server build: an externalised dependency is imported from// node_modules at runtime rather than transformed.ssr: { noExternal: ['@astryx-svelte/core'] }});
Written by hand, these options must match this package's own build exactly, or the atomic CSS
you compile differs from the output verified against upstream. The preset is the only form in which
"exactly" stays true without anyone maintaining it.
</details>
Both
optimizeDeps.exclude and ssr.noExternal fail silently when missing. If a page renders with
the right markup and none of the styling, check those two first.Component Docs
Look up any component's full API — props, variants, examples, best practices, and theming — through
the CLI:
bashpnpm exec astryx-svelte component --list # every component, groupedpnpm exec astryx-svelte component Button # full docs for one componentpnpm exec astryx-svelte util --list # the runes-based composablespnpm exec astryx-svelte search button # components, utils, docs and templates at once
Everything is exported from the package root. There are no per-component subpath entrypoints —
Astryx publishes one per component and this port publishes none, so
@astryx-svelte/core is where
Button lives and the barrel is tree-shaken by your bundler. The subpaths that do exist are for
non-component surfaces:| Subpath | What it is |
|---|---|
@astryx-svelte/core | Every component, every util, every props type |
@astryx-svelte/core/theme | Theme, useTheme, the token vars |
@astryx-svelte/core/theme/define | defineTheme and its types, for authoring a theme |
@astryx-svelte/core/theme/syntax | Syntax-highlighting themes for CodeBlock |
@astryx-svelte/core/hooks | The composables, without the components |
@astryx-svelte/core/utils | Framework-free helpers |
@astryx-svelte/core/naming | The class-name helpers themes and integrations build against |
@astryx-svelte/core/i18n | The message catalog runtime |
@astryx-svelte/core/locales/* | The shipped catalogs (en, fr-FR, pseudo) |
@astryx-svelte/core/vite | The astryx() Vite preset, for compiling from source |
@astryx-svelte/core/base.css | Layer order and color-scheme — always needed |
@astryx-svelte/core/astryx.css | Every component's styles, pre-built — see above |
Page Layouts
Building a full page? Astryx's advice is to start from a template rather than composing from
scratch, and the CLI has the command:
bashpnpm exec astryx-svelte template --list # browse page and block templatespnpm exec astryx-svelte template <id> --skeleton
43 page templates ship today — dashboards, chat, settings, auth, pricing and more — and every id
matches upstream's.
template <id> --skeleton prints the structure; without it you get the whole
page.Upstream also ships ~614 block templates, the smaller compositions you drop inside a page. Those
are React source and are still being ported, so
--list shows the page set only. Templates
contributed by an integration or by any other installed package are discovered and injected the same
way.Related Packages
| Package | Description |
|---|---|
@astryx-svelte/cli | Component docs, reference topics, themes, scaffolding, codemods |
@astryx-svelte/theme-neutral | The default Astryx look — muted and minimal |
@astryx-svelte/theme-butter | Warm creamy yellows with a friendly blue accent |
@astryx-svelte/theme-chocolate | Rich cozy browns with Fraunces headings |
@astryx-svelte/theme-gothic | Deep blue-grays and a display serif; dark-only |
@astryx-svelte/theme-matcha | Earthy greens, calm and organic |
@astryx-svelte/theme-stone | Warm stone and slate, understated |
@astryx-svelte/theme-y2k | Hot pinks, lime greens, and Poppins |
@astryx-svelte/theme-liquid-glass | macOS translucent materials; no upstream counterpart |