AuraProvider
Sets the four data-* attributes that drive the whole token stylesheet, and exposes the current values plus setters. Token overrides go through vars as inline custom properties (CSSOM), so a strict style-src CSP is respected.
Code
<!-- No provider component needed: the four axes are attributes on the root,
and every token below re-resolves from them. -->
<html data-theme="dark" data-accent="iris" data-corner="rounded" data-density="comfortable">
<button class="aura-btn aura-btn--primary">Now iris, on a dark canvas</button>
</html>
<script>
// Switching a theme is one attribute write — no re-render, no context.
document.documentElement.setAttribute('data-accent', 'sunset');
</script>import { AuraProvider, Button, Card, Stack, Typography, useAura } from '@ilomee/aura-react';
function ThemeReadout() {
const { theme, accent, setTheme } = useAura();
return (
<Stack gap={3}>
<Typography variant="caption" tone="muted">
This subtree is pinned by its own provider: {theme} / {accent}
</Typography>
<Button variant="primary" onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle just this card
</Button>
</Stack>
);
}
export default function Demo() {
// A provider scopes theming to a subtree — the page around it is unaffected.
return (
<AuraProvider defaultTheme="dark" defaultAccent="iris">
<Card elevation="raised">
<ThemeReadout />
</Card>
</AuraProvider>
);
}useAura() returns { theme, accent, corner, density, setTheme, setAccent, setCorner, setDensity } and throws outside a provider.
<script setup lang="ts">
import { ref } from 'vue';
import { AuraProvider, Button } from '@ilomee/aura-vue';
const theme = ref<'light' | 'dark'>('light');
</script>
<template>
<AuraProvider v-model:theme="theme" default-accent="iris">
<Button variant="primary">Themed</Button>
</AuraProvider>
</template>All four axes support v-model — more symmetric than React, which lacks corner/density callbacks. useAura() is available via the exported AuraInjectionKey.
<script lang="ts">
import { AuraProvider, Button } from '@ilomee/aura-svelte';
let theme = $state<'light' | 'dark'>('light');
</script>
<AuraProvider bind:theme accent="iris">
<Button variant="primary">Themed</Button>
</AuraProvider>useAura() returns { theme, accent, corner, density, setTheme, setAccent, setCorner, setDensity }. The setters write through the bindable props, so bind:theme on the caller still sees the change.
Used as [auraTheme] — a directive you put on your own element.
import { inject } from '@angular/core';
import { AuraTheme, AuraThemeService, AuraButton } from '@ilomee/aura-angular';
@Component({
standalone: true,
imports: [AuraTheme, AuraButton],
// Unbound axes track the service, so setTheme() below repaints the subtree.
template: `
<div auraTheme>
<button auraButton variant="primary" (click)="toggle()">Themed</button>
</div>
`,
})
export class DemoComponent {
private readonly svc = inject(AuraThemeService);
toggle(): void {
this.svc.theme.set(this.svc.theme() === 'light' ? 'dark' : 'light');
}
}A directive plus a root-provided AuraThemeService of signals. Each axis follows the service unless you bind that input, which pins it — and each emits when it moves, so [(theme)] writes back.
Props
| Name | Type | Default | Notes |
|---|---|---|---|
| theme | 'light' | 'dark' | — | Controlled. |
| defaultTheme | 'light' | 'dark' | 'light' | |
| onThemeChange | (t: Theme) => void | — | |
| accent | Accent | — | One of the 10 accents. |
| defaultAccent | Accent | 'aqua' | |
| onAccentChange | (a: Accent) => void | — | |
| corner | 'rounded' | 'sharp' | 'pill' | — | |
| defaultCorner | 'rounded' | 'sharp' | 'pill' | 'rounded' | |
| onCornerChange | (c: Corner) => void | — | |
| density | 'comfortable' | 'compact' | — | |
| defaultDensity | 'comfortable' | 'compact' | 'comfortable' | |
| onDensityChange | (d: Density) => void | — | |
| vars | Record<`--${string}`, string> | — | Token overrides applied to the wrapper. |
| as | 'div' | 'section' | 'main' | 'div' |
| Name | Type | Default | Notes |
|---|---|---|---|
| themetwo-way | Theme | — | Two-way via v-model:theme. |
| accenttwo-way | Accent | — | |
| cornertwo-way | Corner | — | |
| densitytwo-way | Density | — | |
| defaultTheme | Theme | 'light' | |
| defaultAccent | Accent | 'aqua' | |
| defaultCorner | Corner | 'rounded' | |
| defaultDensity | Density | 'comfortable' | |
| vars | Record<string, string> | — | |
| as | string | 'div' | |
| update:themeevent | (t: Theme) => void | — | |
| update:accentevent | (a: Accent) => void | — | |
| update:cornerevent | (c: Corner) => void | — | |
| update:densityevent | (d: Density) => void | — |
| Name | Type | Default | Notes |
|---|---|---|---|
| themetwo-way | Theme | 'light' | $bindable. |
| accenttwo-way | Accent | 'aqua' | |
| cornertwo-way | Corner | 'rounded' | |
| densitytwo-way | Density | 'comfortable' | |
| vars | Record<string, string> | — | |
| as | 'div' | 'section' | 'main' | 'div' |
| Name | Type | Default | Notes |
|---|---|---|---|
| themetwo-way | Theme | — | Leave unset to follow AuraThemeService. |
| accenttwo-way | Accent | — | Leave unset to follow AuraThemeService. |
| cornertwo-way | Corner | — | Leave unset to follow AuraThemeService. |
| densitytwo-way | Density | — | Leave unset to follow AuraThemeService. |
| vars | Record<string, string> | — | Token overrides written to the host as custom properties. |
| themeChangeevent | (t: Theme) => void | — | |
| accentChangeevent | (a: Accent) => void | — | |
| cornerChangeevent | (c: Corner) => void | — | |
| densityChangeevent | (d: Density) => void | — |
Emitted classes
Every framework emits the same classes — that is what makes the four libraries look identical. You can use them directly, without any component library.
| Class | Role | Notes |
|---|---|---|
| [data-theme] | base | Required. A modifier does nothing without it. |
| [data-accent] | base | Required. A modifier does nothing without it. |
| [data-corner] | base | Required. A modifier does nothing without it. |
| [data-density] | base | Required. A modifier does nothing without it. |