A type-safe styling library for React components built on top of [Vanilla Extract](https://vanilla-extract.style/). `@noema/motif` allows you to create styled components with consistent theme-aware props that cleanly separate styling from component logic.
npm install @noema/motifA type-safe styling library for React components built on top of Vanilla Extract. @noema/motif allows you to create styled components with consistent theme-aware props that cleanly separate styling from component logic.
@vanilla-extract/css and @vanilla-extract/sprinkles will also need to get installed.
``bash`
npm install @noema/motif @vanilla-extract/css @vanilla-extract/sprinkles
`typescript
// styles.css.ts
import { createSprinkles, defineProperties } from '@vanilla-extract/sprinkles';
import { motifStyle } from '@noema/motif';
// Define your style properties
export const styles = motifStyle(
[
'width',
'height',
'fontSize',
// Add more CSS properties as needed
],
{
shorthands: {
// Define shorthands if needed
size: ['width', 'height'],
},
},
);
// Define your sprinkles (theme-based properties)
const colorProperties = defineProperties({
properties: {
color: {
primary: 'blue',
secondary: 'purple',
// Add more theme colors
},
backgroundColor: {
primary: 'white',
secondary: 'lightgray',
// Add more theme colors
},
},
});
export const sprinkles = createSprinkles(colorProperties);
`
`typescript
// components.tsx
import { createMotif, motif } from '@noema/motif';
import { sprinkles, styles } from './styles.css';
// Creae a single component
const BoxComp = motif('div', sprinkles, styles);
// Or multiple components
const elements = ['div', 'button', 'span', 'h1'] as const;
// Create your styled components
export const Styled = createMotif(elements, sprinkles, styles);
// Export individual components for convenience
export const { div: Box, button: Button } = Styled;
`
`tsx
import { Box, Button } from './components';
function MyComponent() {
return (
);
}
`
Creates a style configuration for use with motif or createMotif.
Parameters:
- properties: Array of CSS property names to be controlled via propsoptions
- : Configuration optionsprefix
- : Prefix for CSS variable names (default: 'motif')base
- : Base styles to apply to all componentsshorthands
- : Record of shorthand property names mapping to CSS properties
Returns: Style configuration object
Creates a collection of styled components.
Parameters:
- elements: Array of HTML element types to create components forsprinkles
- : Vanilla Extract sprinkles functionconfig
- : Style configuration created with motifStyle
Returns: Object with styled components for each element
Core function that creates a single styled component.
Parameters:
- element: HTML element typesprinkles
- : Vanilla Extract sprinkles functionconfig
- : Style configuration created with motifStyle
Returns: Styled React component
Motif combines two styling approaches to create a powerful and flexible styling system:
1. motifStyle - Defines which CSS properties can be used as component props
- Creates CSS variables for each property
- Generates CSS classes that apply these variables
- Allows defining shorthand props (like p for all paddings)
2. Runtime Styling Flow
- When you pass props to a motif component (e.g., width={200}):
- The value is converted to a CSS variable value
- The corresponding CSS class is applied to the component
- The CSS variable is set as an inline style
This hybrid approach enables:
- Type safety through TypeScript
- Performance of atomic CSS
- Flexibility of runtime values via CSS variables
- Theme consistency via Vanilla Extract's design system
`typescript
// primitives.css.ts
import { createSprinkles, defineProperties } from '@vanilla-extract/sprinkles';
import { motifStyle } from './motif-style.js';
export const styles = motifStyle(
[
'width',
'height',
'minHeight',
'minWidth',
'maxWidth',
'maxHeight',
'gridTemplateColumns',
'gridTemplateRows',
'gridTemplateAreas',
'gridColumn',
'gridRow',
'gridArea',
'top',
'bottom',
'left',
'right',
'zIndex',
'fontSize',
],
{ shorthands: {} },
);
// Structural properties for layout
const structureProperties = defineProperties({
properties: {
display: ['none', 'flex', 'block', 'inline', 'grid'],
flexDirection: ['row', 'column'],
// ... more properties
},
});
// Box style with padding shorthands
export const boxStyle = motifStyle(
['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'],
{
shorthands: {
py: ['paddingTop', 'paddingBottom'],
px: ['paddingLeft', 'paddingRight'],
p: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'],
},
},
);
export const sprinkles = createSprinkles(structureProperties);
`
`typescript
// primitives.tsx
import { MotifComponents, createMotif } from './create-motif.js';
import { sprinkles, styles } from './primitives.css.js';
const NODES = [
'button',
'div',
'h1',
'h2',
'h3',
'span',
'table',
'thead',
'tbody',
'th',
'tr',
'td',
] as const;
// Create primitive components
export const Primitive = createMotif(NODES, sprinkles, styles);
export type PrimitiveProps = MotifComponents
// Export common components
export const { button: Button, div: Box } = Primitive;
`
The library also includes additional utilities:
- createContext - A utility for creating React context with improved type safety and error messagescomposeRender` - A utility for composing render props with improved type safety
-
MIT