Tokenami provides several utility types to help you build type-safe components with full autocomplete support for your design tokens.
Variants
The Variants type extracts the available variant options from a composed style, allowing you to extend your component props with type-safe variant selection.
Type signature
type Variants<T> = T extends TokenamiComposeOutput<infer V> ? CSSVariants<V> : {};
Usage
Use Variants to type component props that accept variant options:
import { css, type Variants } from '@tokenami/css';
const button = css.compose({
'--background': 'var(--color_primary)',
'--color': 'var(--color_white)',
'--padding': 4,
variants: {
size: {
small: { '--padding': 2 },
large: { '--padding': 6 },
},
color: {
blue: { '--background-color': 'var(--color_blue)' },
green: { '--background-color': 'var(--color_green)' },
},
},
});
type ButtonElementProps = React.ComponentPropsWithoutRef<'button'>;
interface ButtonProps extends ButtonElementProps, Variants<typeof button> {}
function Button({ size, color, ...props }: ButtonProps) {
const [cn, css] = button({ size, color });
return <button {...props} className={cn(props.className)} style={css(props.style)} />;
}
Now TypeScript will enforce valid variant values:
// ✅ Valid
<Button size="small" color="blue" />
// ❌ TypeScript error - invalid size
<Button size="tiny" color="blue" />
TokenamiStyle
The TokenamiStyle type extends a component’s props to accept Tokenami properties in the style prop. This enables consumers to pass Tokenami CSS variables with full type checking and autocomplete.
Type signature
type TokenamiStyle<P> = P & { style?: TokenamiProperties | TokenamiCSS };
Usage
Use TokenamiStyle to make your components accept Tokenami properties:
import { type TokenamiStyle, css } from '@tokenami/css';
interface ButtonProps extends TokenamiStyle<React.ComponentProps<'button'>> {
variant?: 'primary' | 'secondary';
}
function Button({ variant = 'primary', ...props }: ButtonProps) {
return (
<button
{...props}
style={css(
{
'--background': 'var(--color_primary)',
'--padding': 4,
},
variant === 'secondary' && {
'--background': 'var(--color_secondary)',
},
props.style
)}
/>
);
}
Now you can pass Tokenami properties with full type safety:
// ✅ TypeScript provides autocomplete for Tokenami properties
<Button style={{ '--padding': 6, '--color': 'var(--color_white)' }} />
// ✅ Type checking ensures valid token values
<Button style={{ '--background': 'var(--color_primary)' }} />
TokenValue
The TokenValue type generates a union of CSS variable tokens for a specific theme key. Use it when you need to reference theme tokens in your TypeScript code.
Type signature
type TokenValue<ThemeKey extends string> =
| TokensByThemeKey[ThemeKey]
| (ThemeKey extends 'grid' | 'number' ? Tokenami.GridValue : never);
Usage
Given this theme configuration:
import { createConfig } from '@tokenami/css';
export default createConfig({
theme: {
color: {
'slate-100': '#f1f5f9',
'slate-700': '#334155',
'sky-500': '#0ea5e9',
},
radii: {
rounded: '10px',
circle: '9999px',
none: 'none',
},
},
});
You can extract specific token types:
import { type TokenValue } from '@tokenami/css';
type Color = TokenValue<'color'>;
// Result: 'var(--color_slate-100)' | 'var(--color_slate-700)' | 'var(--color_sky-500)'
type Radii = TokenValue<'radii'>;
// Result: 'var(--radii_rounded)' | 'var(--radii_circle)' | 'var(--radii_none)'
This is useful for creating typed component APIs that accept specific tokens:
interface CardProps {
borderColor?: TokenValue<'color'>;
borderRadius?: TokenValue<'radii'>;
}
function Card({ borderColor, borderRadius, children }: CardProps) {
return (
<div
style={css({
'--border-color': borderColor ?? 'var(--color_slate-100)',
'--border-radius': borderRadius ?? 'var(--radii_rounded)',
'--border-width': 1,
})}
>
{children}
</div>
);
}
// Usage with type safety
<Card
borderColor="var(--color_sky-500)"
borderRadius="var(--radii_circle)"
>
Content
</Card>
For grid values, TokenValue also accepts numbers since Tokenami multiplies numeric values by your grid size.
Best practices
Combine utility types
You can combine multiple utility types for comprehensive type safety:
import { type TokenamiStyle, type Variants, css } from '@tokenami/css';
const card = css.compose({
'--padding': 4,
'--border-radius': 'var(--radii_rounded)',
variants: {
elevation: {
flat: { '--box-shadow': 'none' },
raised: { '--box-shadow': 'var(--shadow_md)' },
},
},
});
interface CardProps
extends TokenamiStyle<React.ComponentProps<'div'>>,
Variants<typeof card> {
children: React.ReactNode;
}
function Card({ elevation, children, ...props }: CardProps) {
const [cn, style] = card({ elevation });
return (
<div {...props} className={cn(props.className)} style={style(props.style)}>
{children}
</div>
);
}
Type custom hook returns
Use utility types when building custom styling hooks:
import { type TokenamiCSS } from '@tokenami/css';
function useButtonStyles(variant: 'primary' | 'secondary'): TokenamiCSS {
return css({
'--background': variant === 'primary'
? 'var(--color_primary)'
: 'var(--color_secondary)',
'--color': 'var(--color_white)',
'--padding': 4,
});
}