Skins
An optional look you switch on with one attribute, built from three variables the components already read.
Last updated
A skin changes how controls are drawn without touching a component. The base
theme defines three inert variables; a skin file redefines them under
[data-skin="<name>"]. Put the attribute on <html> for the whole site or on
any element for a subtree, and remove it to go back. The docs navbar has a
skin switch next to the theme switch, so you can preview every page both ways.
| Variable | Default | Read by |
|---|---|---|
--shadow-control |
none | solid and outline Buttons, pressed ToggleButtons, the selected SegmentedControl chip |
--highlight-control |
transparent | the inner top highlight of solid Buttons |
--shadow-field |
none | outlined text fields |
Skeuomorphic
The first skin: a bevel and a top sheen on buttons and checked controls, inset wells for fields and unchecked boxes, and a lit edge with a soft shadow on surfaces (cards, choice cards, menus, popovers, dialogs, toasts, featured icons). Both themes are tuned separately.
A card picks up the lit edge.
Show codeHide code
<div data-skin="skeuomorphic">
<Button>Save</Button>
<Button variant="outline" color="neutral">Cancel</Button>
<Input label="Email" placeholder="you@example.com" />
<SegmentedControl name="view" options={[{ value: 'list', label: 'List' }, { value: 'grid', label: 'Grid' }]} value="list" />
</div>The demo above follows the navbar switch. A subtree can opt in on its own:
Show codeHide code
<Button>Plain page</Button>
<div data-skin="skeuomorphic"><Button>Skinned region</Button></div>Enable it
npx @ava-ui/apogee init --skin skeuomorphic # writes src/styles/apogee-skin-skeuomorphic.css
Or copy registry/tokens/skin-skeuomorphic.css beside your tokens file. Then:
@import "./apogee.css";
@import "./apogee-skin-skeuomorphic.css";
<html data-skin="skeuomorphic">
Switch at runtime with the helpers in utils/theme.ts; the choice persists
under apogee-skin and apogee:skin-change fires on document:
import { getSkin, setSkin } from '@/components/apogee/utils/theme.ts'
setSkin('skeuomorphic') // on
setSkin(null) // off
getSkin() // 'skeuomorphic' | null
Restore it before paint the same way as the theme:
<script is:inline>
const s = localStorage.getItem('apogee-skin')
if (s) document.documentElement.dataset.skin = s
</script>
Writing a skin
A skin is a CSS file that sets the three variables under [data-skin='<name>'],
with a second block for dark mode. It must not touch component classes; if a
look needs more than the variables, add a variable to the base theme first so
every skin can use it.
Do / Don’t
- Do apply it page-wide or to a whole section; mixed controls side by side look like two products.
- Do keep the alphas: the values are ink over any fill, so they work on every hue.
- Don’t nest skins; the inner attribute wins and the seam shows.
- Don’t rely on a skin for contrast: the contrast gate measures the base tokens only.