Cascade layers (@layer)
Opt-in CSS cascade layers for predictable specificity against global CSS
By default, TypeStyles emits flat rules (no @layer), matching legacy behavior and keeping the API surface small.
When you opt in with a layers tuple on createStyles, createTokens, or the unified createTypeStyles factory, TypeStyles:
- Registers a single
@layer a, b, c;preamble (once per distinct stack) so order is deterministic. - Wraps each emitted rule block in
@layer <name> { … }for thelayeryou pass on each style call. - When
createTokens({ layers, tokenLayer })is used,:rootcustom properties and theme rules go intotokenLayerso utilities and components can override tokens predictably.
createTypeStyles (recommended for design systems)
One config object gives you matching scopeId, layers, and tokenLayer for both class CSS and token/theme CSS:
import { createTypeStyles } from 'typestyles';
const { styles, tokens } = createTypeStyles({
scopeId: 'ds',
mode: 'semantic',
layers: ['reset', 'tokens', 'components', 'utilities'] as const,
tokenLayer: 'tokens',
});
const reset = styles.class('reset', { margin: 0, padding: 0 }, { layer: 'reset' });
const button = styles.component(
'button',
{
base: { padding: '8px 16px' },
variants: {
intent: { primary: { backgroundColor: '#0066ff' } },
},
defaultVariants: { intent: 'primary' },
},
{ layer: 'components' },
);
tokens.create('color', { primary: '#0066ff' });
Conceptual output:
@layer reset, tokens, components, utilities;
@layer tokens {
:root {
/* --ds-color-* */
}
}
@layer reset {
.reset {
margin: 0;
padding: 0;
}
}
@layer components {
.button-base {
padding: 8px 16px;
}
}
createStyles only
Pass layers as a const tuple (or as { order, prependFrameworkLayers? }). Every styles.class, styles.hashClass, and styles.component call must include { layer: '…' }. Layer names must appear in the tuple (not in prependFrameworkLayers, which only affects ordering against external frameworks).
const styles = createStyles({
layers: { order: ['components'], prependFrameworkLayers: ['bootstrap'] },
});
styles.class('card', { padding: '1rem' }, { layer: 'components' });
createTokens with layers
When layers is set, tokenLayer is required. Token and theme CSS is wrapped in that layer.
const tokens = createTokens({
scopeId: 'app',
layers: ['tokens', 'components'] as const,
tokenLayer: 'tokens',
});
Default (no layers)
Omit layers everywhere: no @layer in output, and there is no layer option on style APIs.
Notes
- Multiple instances: Each factory that passes
layersowns its own stack; preamble keys includescopeIdand full order so different design systems on one page stay distinct. - Build / SSR: Preamble rules are inserted at the front of the virtual sheet so
getRegisteredCss()and extraction see ordering before wrapped blocks. - jsdom: Older parsers may log warnings for
@layer; real browsers support cascade layers.
See also Class naming.