English
Theme and styles
An app imports two things at minimum: a theme, and structural styles for the components it uses.
ts
import { Button } from '@astryx-vue/core/Button'
import '@astryx-vue/themes/neutral.css'The Button entry loads the structural sheet for button. The theme entry loads Neutral's variables, including the --astryx-button-* names that button reads. Without the theme, the structure is there and the color and metrics are not. Without the structural sheet, the variables have no rules to feed.
To load every structural sheet once, add this at the entry:
ts
import '@astryx-vue/core/styles.css'
import '@astryx-vue/themes/neutral.css'styles.css gathers the sheets in packages/core/styles/, including the shared motion in motion.css. neutral.css gathers the theme files in packages/themes/neutral/ and loads Figtree and JetBrains Mono.
The layer order is:
css
@layer astryx.reset, astryx.tokens, astryx.base, astryx.components, astryx.overrides;Application overrides belong in astryx.overrides. Unlayered global CSS beats these layers, so a bare button { } will paint over the component unless that is what you want.
Using Tailwind or UnoCSS alongside
They work together as long as the layer order is fixed.
One rule matters: the position of every layer on the page is set by where it first appears. The reliable way is to declare all the layers in one statement at the top of your app entry.
css
@layer theme, base, astryx.reset, astryx.tokens, astryx.base, astryx.components, astryx.overrides, components, utilities;
@import 'tailwindcss';
@import '@astryx-vue/core/styles.css';
@import '@astryx-vue/themes/neutral.css';Earlier layers are weaker and later layers win. The utilities layer sits after astryx.components, so class="p-0" beats the padding a component sets. astryx.overrides sits before utilities, so it cannot beat them. When one rule must win over a utility class, do not reach for overrides; reorder the layers, or write the rule unlayered.
One note on syntax: an @layer statement may come before @import. That is one of the few orders CSS allows; the other way round the whole block is discarded as invalid.
Use our variables in utility classes
No config needed; arbitrary values work as they are.
html
<div class="p-[var(--astryx-spacing-4)] text-[var(--astryx-color-text-primary)]">
...
</div>Tailwind v4 can also register the variables as its own tokens, which reads shorter.
css
@theme inline {
--color-surface: var(--astryx-color-background-card);
--color-body: var(--astryx-color-text-primary);
}Then write bg-surface and text-body. Do not drop inline. Tailwind's guidance is that a theme value pointing at another variable needs it; without it the generated utility reads --color-surface itself rather than our variable, and colors scoped to a theme stop following.
UnoCSS
UnoCSS emits utilities as ordinary rules with no layer. Unlayered rules beat any @layer, so utilities win over component styles with no ordering work.
The cost is the mirror image: layered CSS you write cannot beat a UnoCSS class. To override one, write a more specific selector, or write unlayered CSS.
If you turn on UnoCSS's CSS layer output (outputToCssLayers), treat it like Tailwind and place its layers after astryx.components.
Using CSS Modules or plain CSS
Both work. Three things to keep in mind.
Class names do not collide. <style module> and *.module.css rename your classes, so name them freely.
Reaching inside a component takes a doorway. Scoped styles use :deep(); CSS Modules use :global.
vue
<style module>
/* Change the width of one element inside the component */
.panel :global(.astryx-layout__panel) {
width: 420px;
}
</style>Values still come from variables. Your own class names are fine; colors and spacing are still var(--astryx-*). Slipping a #171717 in breaks both dark mode and theming.
If the project uses no layers at all, write specific selectors. Avoid bare element selectors such as button { }, and avoid a global * { }.
These styles do not require UnoCSS. The docs site uses UnoCSS only so example classes such as i-carbon-* can draw icons. That is the icon approach, not a styling dependency. See Icons.
Variable names, light-dark(), and what the theme covers today are in CSS variables and Neutral.