Styling
Style Wave components and build your own styled components.
Wave components accept className and style props, so you can style them with plain CSS, CSS Modules or any other approach you already use.
Wave also provides its own styling APIs: styled(), the css prop and css(). They give you design tokens, breakpoints and variants, with autocompletion in TypeScript. Prefer them when you customise Wave components or build your own.
styled()#
styled() creates a component with styles attached. Wave builds its own components with it. Pass it an HTML element or any component and a style object.
The style object is a superset of CSS: it takes all CSS properties and selectors, plus design tokens, breakpoints and utilities:
import { styled } from '@volue/wave-react';const Panel = styled('div', {// write standard CSSdisplay: 'grid',// access design tokensbackgroundColor: '$backgroundNeutralSubtle',padding: '$spacingM',// write responsive styles'@mqLargeAndUp': {padding: '$spacingL'},// use shorthand utilitiesmb: '$spacingXl'});
When working in a TypeScript codebase our design token options will show up with autocompletion depending on the CSS property used.
Pass a Wave component to build on it. The new component keeps the props of the component it wraps:
import { Flex, styled } from '@volue/wave-react';const Toolbar = styled(Flex, {borderBottom: '1px solid $borderNeutralSubtle',padding: '$spacingS'});() => (<Toolbar main="space-between" cross="center">{children}</Toolbar>);
In addition to the base component styles, styled() lets you define variants: styles that apply based on the props you pass.
Variants can be applied conditionally or responsively:
import { styled } from '@volue/wave-react';const Panel = styled('div', {display: 'grid',variants: {size: {small: { gap: '$spacingS' },large: { gap: '$spacingL' }},bordered: {true: { border: '1px solid $borderNeutralSubtle' }}}});() => (<Panel size={{ '@initial': 'small', '@mqLargeAndUp': 'large' }} bordered />);
Use styled() by default: define the styles once, give them a name and reuse the component wherever you need it.
css prop#
Every Wave component, and every component you create with styled(), accepts a css prop. It takes the same style object and applies it as a class on that one instance. Unlike inline styles, it can use design tokens, breakpoints and utilities:
import { Box } from '@volue/wave-react';<Boxcss={{padding: '$spacingM','@mqLargeAndUp': {padding: '$spacingL'}}}/>;
Box is a plain div made with styled(). Use it when you need an element to style without creating a component.
Use the css prop for one-off adjustments to a single instance:
- When you repeat the same styles, move them into a
styled()component. - When styles depend on a condition, define variants instead of building the
cssobject conditionally. - When values change often, such as a position that follows the pointer, pass them in
style. Each distinctcssobject adds a new CSS rule to the page, and the rule stays there.
Wave's styling APIs are built on a fork of Stitches.
css()#
css() creates a reusable style function with the same object syntax and variants as styled(). Use it to share styles between components, or to style an element you don't create with styled(), such as a third-party component.
To share styles, compose the function into styled(), which renders its styles for you:
import { css, styled } from '@volue/wave-react';const cardCss = css({padding: '$spacingM',variants: { size: { small: { padding: '$spacingS' } } }});const CardRoot = styled('div', cardCss);const CardLink = styled('a', cardCss, { textDecoration: 'none' });
To style another element, call the function and pass its className to the element. Render the styles of the call next to it: they carry the CSS for that class name when the page renders on the server:
function CardChart({ size, ...props }) {const card = cardCss({ size });return (<>{card.styles}<ThirdPartyChart {...props} className={card.className} /></>);}
Server components#
With WaveStyles set up, the css prop, styled() and css() work in React Server Components as they do in the browser: the CSS travels with the elements they style. Wave's own components are client components.
One exception: a styled server component cannot be the child of a component that passes its props to that child, such as the triggers of Tooltip, Popover and Menu, or as={Slot}. On the server, React renders a styled component as two nodes, its element and its <style> elements. Add 'use client' to the file that defines the styled component, so that it reaches them as one element.