Skip to content
helia-ui
Sections
HELIA HUB

helia-ui

@ambiqai/helia-ui is the shared design system behind the HELIA developer surfaces: the tokens, the Astro parts, the shadcn React components, and the Starlight theme. It ships as source with no build step, so a consuming site’s bundler reads the stylesheets and components directly.

This site is one of its consumers. Every page here reaches the package through the export map and the Starlight plugin, never by relative path, so what you read on a page is what an unrelated site gets.

Terminal window
npm install @ambiqai/helia-ui

Because the package ships source rather than a bundle, the consuming site supplies the toolchain. These are peer dependencies and the site needs the same majors:

PeerRange
astro^7.0.2
@astrojs/starlight^0.41.5
react^19
react-dom^19
tailwindcss^4.3.3

A site wires the package in three places: the Starlight plugin in astro.config.mjs, its own Tailwind entry, and the React integration if it uses the React lane.

astro.config.mjs
import { heliaStarlight } from '@ambiqai/helia-ui/starlight';
export default defineConfig({
integrations: [
starlight({
customCss: ['./src/styles/tailwind.css'],
plugins: [heliaStarlight({ footer: { links, tagline } })],
}),
react(),
],
vite: { plugins: [tailwindcss()] },
});
src/styles/tailwind.css
@import '@ambiqai/helia-ui/starlight-tailwind.css';
@source '../content/**/*.{md,mdx}';
@source '../components/**/*.{astro,tsx}';
@source '../../node_modules/@ambiqai/helia-ui/astro/**/*.astro';
ExportWhat it is
./tokens.cssPrimitives for both themes, and the mapping onto Starlight’s --sl-* variables
./semantic.cssSpacing, radius, type, weight, leading, ink, surfaces, tones
./recipes.csshelia-surface, chip, eyebrow, button, card, badge, media, and the focus and hover recipes
./starlight.cssUnlayered chrome overrides: sidebar, header, search, table of contents, steps, skinned built-ins
./tailwind.cssLayer order and the @theme mapping, with no Starlight dependency
./starlight-tailwind.css./tailwind.css with @astrojs/starlight-tailwind in front; what a Starlight site imports
./shadcn.cssThe shadcn variable bridge, imported by ./tailwind.css
./astro/*The Astro parts, one file per part
./react/*The generated shadcn components, one file per component
./starlightThe heliaStarlight() plugin
./starlight/*The shell components the plugin installs

The four stylesheets the plugin injects are unlayered on purpose. Unlayered rules beat every cascade layer, so the token sheets stay the source of truth no matter what the Starlight Tailwind compat package wires up below them. See the Starlight plugin for the injection order.

The package offers three ways to put something on a page, and the choice is not a matter of taste.

Astro parts (./astro/*) are the default. Surface, the card family, Badge, Chip, Button, Media, the carousel: static presentation with zero JavaScript, no React at build time, inline in MDX. Reach for these first.

React components (./react/*) are the generated shadcn layer, for behavior a browser cannot do alone: focus trapping, roving focus, filtered lists, popovers that flip, sorting and paging, charts. Do not re-base an Astro part on shadcn to get a class name.

Stylesheets (./tokens.css and the rest) carry the vocabulary both lanes compile against, plus the Tailwind @theme mapping so utilities and parts use one spacing and color scale. @theme inline keeps a generated utility referencing the token directly rather than a value snapshotted at :root, which is what lets utilities follow the theme toggle.

Two starters ship in the repository rather than in the published tarball, so a new surface begins wired up rather than assembled by hand.

Docs sites (templates/product-docs) is a Starlight site with the plugin, the Tailwind entry and KaTeX already in place.

Web apps (templates/web-app) is a Vite, React and TypeScript application for live hardware and streaming data: a worker that produces samples, a ring buffer that publishes one frame at a time, a Recharts trace, and the Source interface a device driver implements. Docs and marketing pages ship no JavaScript; an app’s bar is responsiveness under streaming instead.

Every part in ./astro/* holds to four rules. They are what makes the package publishable rather than one site’s own components.

  1. Composition over configuration. More than about six props means a composition wearing a primitive’s name. Regions are children or named slots, never a title / description / action prop bundle.
  2. Data enters through props and children only. No part imports data, and no part knows what a product, a demo, or a status is.
  3. Actions are handed in as children. A card never decides where it links.
  4. No domain vocabularies. Status names, brand marks, and product accents are the consumer’s. The package exposes Badge tone and --accent, and the consumer decides what “Released” looks like.

Where a part takes a spacing prop it names a step ('4', 'none') rather than a length, so the value resolves through the same scale as every utility.

React context does not cross Astro’s MDX component boundary. Astro gives each component in an .mdx file its own React root and passes children through as serialized HTML, so a compound component assembled in a page throws at build with `TabsTrigger` must be used within `Tabs`. That covers Tabs, Dialog, Sheet, Select, Combobox, Accordion, Command, Popover, DropdownMenu, and most of the library.