# Wave Design System Documentation > Wave design system provides tools, components and guidance to ensure a unified, cohesive user experience across Volue's product landscape. # Get started ## Developing Wave has everything you need to get started building web interfaces at Volue. Develop a consistent and accessible user interfaces much faster using a range of pre-built components. ### Developing ### Authenticating to package registry Since `@volue` is a private NPM scope, your project (both locally and in CI pipeline) needs to be authenticated with NPM registry to fetch packages. Wave packages are published to both official [npmjs.com registry](https://www.npmjs.com/) and our organization's [Github Package Registry](https://github.com/orgs/Volue/packages). {'NPM'} {'GitHub packages'} The best way to authenticate with [npmjs.com registry](https://www.npmjs.com/) is using an [access token](https://docs.npmjs.com/about-access-tokens). You can find pre-generated authentication token with read-only permissions required to download Wave packages in the [wiki page on GitHub](https://github.com/Volue/wave/wiki/NPM-authentication-token). ```bash # 1. Do this on your local machine and commit the `.npmrc` to git cd path/to/your/app echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' >> .npmrc # 2. Add this environment variable locally # Substitute `READ_ONLY_NPM_TOKEN` with a real token: # https://github.com/Volue/wave/wiki/NPM-authentication-token export NPM_TOKEN=READ_ONLY_NPM_TOKEN # 3. When using Github Actions for CI/CD pipeline, point `NPM_TOKEN` environment # variable to org-wide `secrets.VOLUE_PLATFORM_NPM_TOKEN`, otherwise define a new # secret using the token from previous step. ``` If, for some reason, you're not able to access the [NPM authentication token page](https://github.com/Volue/wave/wiki/NPM-authentication-token), please contact the [Design System team](https://github.com/orgs/Volue/teams/design-system). By default, the `npm` CLI utility is configured to download packages from [official NPM registry](https://www.npmjs.com/). To fetch Wave from [Github Packages](https://docs.github.com/packages), you need to change registry url and specify a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) with read-only permissions inside _.npmrc_ file. ```bash # 1. Do this on your local machine and commit the `.npmrc` to git cd path/to/your/app cat > .npmrc << EOF registry=https://npm.pkg.github.com/volue //npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_PAT} EOF # 2. Add this environment variable both locally and on your CI/CD # Substitute `READ_ONLY_GITHUB_PAT` with a real token: export GITHUB_PACKAGES_PAT=READ_ONLY_GITHUB_PAT ``` `READ_ONLY_GITHUB_PAT` should be a [classic personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#personal-access-tokens-classic) with `read:packages` scope. --- ### Installation Inside your project directory, install Wave by running either of the following: ```bash npm install @volue/wave @volue/wave-react --save ``` ```bash yarn add @volue/wave @volue/wave-react ``` Bleeding edge pre-release version with the most recent features, can be installed by appending `@next` tag to the package names: ```bash yarn add @volue/wave@next @volue/wave-react@next ``` --- ### Include Wave core assets The guide below is useful for custom setups. As long as you're using [one of our starter project templates](#example-react-projects), you can skip these instructions, as these templates are already preconfigured. For Wave to work correctly, you need to include its core assets, such as stylesheets, icons and web fonts. To copy core assets from `node_modules/@volue/wave` to a location where you store your other bundled and minified assets for production, you may use `copy-wave-assets` command: ```bash npx copy-wave-assets ./dist # or yarn copy-wave-assets ./dist ``` `copy-wave-assets` will create a directory named `wave` in the location you’ve specified (`./dist` in the example above). See `copy-wave-assets -h` for more information. It is recommended to add a script to your `package.json` that runs `copy-wave-assets` and call it whenever the build is executed to make sure you’ve always got the latest assets copied over: ```js "scripts": { "sync-wave-assets": "npx copy-wave-assets ./public", "build": "npm run sync-wave-assets && react-scripts build", "start": "npm run sync-wave-assets && react-scripts start" } } ``` Alternatively, you could use tools such as [CopyWebpackPlugin](https://webpack.js.org/plugins/copy-webpack-plugin/) to move core Wave resources to your assets directory as part of your build process. #### Include assets in your HTML template Once you have a copy task in place and and the assets are copied over, you can serve them using `` tags in your root HTML template. - Add links to favicons - Add inline style with @font-face rules in the `` to load initial, highly optimized versions of our web fonts. Remember to preload the initial web fonts using ``. - Inline `wave-head.min.js` in the `` of your HTML template. This is a small chunk of logic that will asynchronously load full versions of our web fonts to enable more stylistic variants and features. `wave-head.min.js` could be specified as `
``` ### Use the components All components are available as named exports from `@volue/wave-react`. Import any of the components in your React project and use them in your interface: ```jsx import { Collapsible, Button, SvgIcon } from '@volue/wave-react'; const Component = () => { return ( {'Toggle panel'} {'Panel content'} ); }; ``` Refer to the individual component documentation for recommended usage and API references for each component. ### Styling APIs #### css The `css` property is available on all of our components to allow you to contextually style them when necessary. It provides a superset of CSS (i.e. it contains all CSS properties and selectors in addition to custom ones) so it's intuitive to pick up and start working with right away if you're comfortable with CSS. You can pass in an object of CSS key-value pairs and the component will apply those styles as a class on the rendered component. The benefit of using the `css` prop as opposed to writing inline styles is that we can directly access values from our design tokens to ensure consistency, write responsive styles by referring to the breakpoints defined in the theme etc: ```jsx import { Box } from '@volue/wave-react'; ; ``` [Box component](/components/layout/box) is a low-level primitive that lets you work with the `css` prop. When working in a TypeScript codebase our design token options will show up with autocompletion depending on the CSS property used. The `css` prop is great for customizing only a specific instance of a given component, by defining one-off styles. #### styled `@volue/wave-react` also exports the underlying `styled()` function that is used to create styled components with access to the `css` prop. ```jsx import { styled } from '@volue/wave-react'; const MyStyledComponent = styled('div', { color: '$foregroundAccent', size: { small: { padding: '$spacingS' }, large: { padding: '$spacingL' } } }); () => ; ``` [Box component](/components/layout/box) is just a `styled` div element. In contrast to the `css` prop, `styled()` function is ideal for building components that need to support a wide variety of contexts. It allows you to create custom components, with similar capabilities as Wave's standard components. In addition to the base component styles, `styled()` lets you define a single variant, multiple variants, and even compound variants which allow you to define styles based on a combination of variants. Those variants can be applied conditionally or responsively. Refer to the [Stitches docs](https://stitches.dev/docs/styling) to read more about the difference between `css` and `styled()`. ### Example React projects Below you will find various project templates on GitHub, demonstrating the integration of Wave with popular bundlers/frameworks and very basic components usage. You might also take a look at our internal boilerplate for developing React apps, which comes integrated with Wave. ## Contributing to Wave No description available ### Overview We gratefully accept contributions to Wave, but expect new feature requests and changes to be discussed with Wave Design System team before [creating a pull request](https://github.com/Volue/wave/wiki/Contributing#pull-request). If you have a question about the project, require support or have some generic idea for improvement, we have a discussion board on GitHub: If you found any bugs in our components, it's best to report them on our GitHub issues board: If you have a proposal for a feature that is not yet available, you can describe it in detail and maybe use images to support it: ### Adding components Before creating a new component, please make sure something similar doesn’t already exist. We follow the below defined process to determine if we should extend an existing component, create a new component, or keep the component application specific instead. We would be happy to spec out together with you how a new component could work and look. ### Dev setup Wave Design System is divided into two main packages: `core` and `react`. Development for all of the packages happens inside one mono repository. Follow the steps in the [monorepo readme](https://github.com/Volue/wave#readme) to get the dev environment up and running. ### Developing components For further advice on how to contribute new components, please refer to our contributing guide on the [Storybook website](https://next--63ac6ba300bd3c91074bc891.chromatic.com). ### Time registration You can officially register time spent on contributing to **Wave** as you would when developing other projects in Volue. ## Composition An overview of component composition patterns in Wave React. ### Compound components The compound components pattern in React is a design strategy for building flexible and reusable components. Instead of creating a single, monolithic component that tries to handle every possible variation through an ever-growing number of props, you break it down into multiple, interconnected components that work together. These components implicitly share state and logic, often using [React Context](https://react.dev/reference/react/createContext) behind the scenes. Transitioning from a monolithic component to compound components inverts control, giving consumers granular access to each part of the larger component as needed. This allows them to: - Compose individual parts with other components or logic. - Control the rendering order and structure. - Add custom props, event listeners, or refs directly to the relevant sub-component. - Apply contextual styles. This approach strikes a balance between simplicity and flexibility. In simple, common cases, consumers can use the components with minimal configuration. However, components remain open for extension and composition with other elements, adapting gracefully to a variety of use cases. Below is an example of using [Popover](/components/popover) and [Form Field](/components/forms/form-field) components to demonstrate the pattern. You compose the desired structure using the provided parts while allowing customization of each part: ```tsx {'Open Popover'} {'First name'} {'Last Name'} {'Cancel'} ``` ### Polymorphism Polymorphism in React allows components to change their underlying rendered element or compose with other components while preserving their core functionality. Wave components support common pattern for achieving polymorphism: the `as` prop. This pattern further enhances reuse and versatility of the components, while being type-safe because props can be correctly inferred based on the provided element or component. `as` prop is especially handy when your goal is to swap out the default HTML element while maintaining the component's behavior and styling. For example, to render a [Button component](/components/button) as an anchor element: ```tsx ``` In the example above, the `Button` component renders as an `` tag, inheriting all the props specific to anchor elements, such as `href` and `target`. The `as` prop can also be used to render another component, enabling composition of behavior: ```tsx {'Open Popover'} {'Popover content'} {'Close'} ``` In the example above, the `Popover.Trigger` and `Popover.Close` render as the `Button` component, inheriting its props while maintaining its own behavior. In frameworks like [Next.js App Router](https://nextjs.org/docs/app), you can use `as` to render [Next.js Link component](https://nextjs.org/docs/pages/api-reference/components/link) that handles routing. This is useful when you want to maintain the behavior of a Wave component while also providing navigation functionality: ```tsx import Link from 'next/link'; function MainNav() { return ( ); } ``` The `as` prop has some limitations by default, as it only accepts a single element or component. However, you can use the `as` prop with a [Slot utility](/components/utility/slot), allowing for composing more than two components together: ```tsx {'Dialog trigger with a link appearance'} {'Dialog content'} {'Close'} ``` The trade-off is that you lose some type safety compared to passing component directly to `as` prop. With `Slot` rendering is delegated to the child element or component, thus the strict contract between parent and child is lost. #### Best practices for creating compatible components When creating your own custom components that are intended to work seamlessly as targets for the `as` prop, follow these practices to make them open for extension: - Ensure your component spreads all incoming props onto the underlying DOM element or component it renders. - Chain the event props with the internal event handlers, if any. - Combine any incoming `style` or `className` props with your component's internal styles or classes. - Use `React.forwardRef` to accept a ref and forward it to the underlying DOM element. If your component uses an internal ref, merge the forwarded ref with your internal one. For example: ```tsx const MyButton = React.forwardRef((props, forwardedRef) => ( ``` ##### Complex buttons layout ```jsx ``` #### Flex item You can use `FlexItem` component to control how a flex item will behave inside a `Flex` container. `FlexItem` exposes properties such as `flex`, `grow` and `shrink`. You can also change `cross` alignment and `order` on an individual flex item. ##### flex `flex` property sets how a `FlexItem` will grow or shrink to fit the available space. ###### flex="initial" (default) The item is sized according to its content or the value of its width and height properties. It shrinks to its minimum size to fit the container, but does not grow to absorb any extra free space in the flex container. This is equivalent to `flex: 0 1 auto` in CSS and is the default behavior for the children elements within a `Flex` container. ```jsx ``` ###### flex="1" The item will grow to absorb any extra free space in the flex container and shrink as needed to fit the container without taking its initial size into account. This is equivalent to `flex: 1 1 0%` in CSS. Useful to set all items to be of equal width no matter their content. ```jsx ``` ###### flex="auto" The item is sized according to its content or the value of its width and height properties, but grows to absorb any extra free space in the flex container, and shrinks to its minimum size to fit the container. This is equivalent to `flex: 1 1 auto` in CSS. ```jsx ``` ###### flex="none" The item is sized according to its content or the value of its width and height properties. It is fully inflexible: it neither shrinks nor grows in relation to the flex container. ```jsx Item that can grow or shrink if needed Item that cannot grow or shrink Item that can grow or shrink if needed ``` ##### grow Use `grow` property to control how `FlexItem` grows. ```jsx Item that cannot grow Item that grows Item that cannot grow ``` ##### shrink Use `shrink` property to control how `FlexItem` shrinks. ```jsx This item will not shrink below its initial size ``` ##### order Use `order` property to render `FlexItem` in a different order than it appears in the source code. ```jsx 1 2 3 ``` ##### alignment Use `crossSelf` property to align individual `FlexItem` on the cross axis. ```jsx ``` ##### Shrinking past content size There is a behavior that can sometimes be surprising when using Flex layout. The content of a `FlexItem` can force it to not shrink properly, for example when you have a long word or URL that you want to truncate. The reason is that flex items won’t shrink below their minimum content size. ```jsx Textwithverylongtitletobefitinthatspaceoktextwithverylongtitletobefitinthatspaceoktextwithverylong ``` You can get around this behavior by setting `shrinkPastContentSize` property which applies `min-width: 0` to the flex item. ```jsx Textwithverylongtitletobefitinthatspaceoktextwithverylongtitletobefitinthatspaceok ``` #### Nesting Multiple `Flex` components can be nested. Below is a demo of a nested structure to create more complex white space rules. ```jsx {'Name'} Email {'Please provide a valid e-mail address.'} ``` --- ### API Reference #### Flex In addition to the props below, you can pass [Box props](/components/layout/box#api-reference) to control the spacing. | Name | Type | Default | Description | Required | | --------- | --------------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | | `as` | `keyof JSX.IntrinsicElements \| React.ComponentType` | `div` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node. For more details, read our [Composition](/get-started/composition#polymorphism) guide. | | | `css` | `StitchesCss` | | Apply styles directly to a component in a similar way how you would define inline styles. Wave uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. | | | `display` | `"flex" \| "inline-flex"` | `"flex"` | Set block or inline display of the flex container. | | | `flow` | `"row" \| "row-reverse" \| "column" \| "column-reverse"` | `"row"` | Set how items are placed in the flex container, defining the main axis and the direction. | | | `main` | `"start" \| "center" \| "end" \| "stretch" \| "space-between" \| "inherit"` | | Alignment of the items across main axis. | | | `cross` | `"start" \| "center" \| "end" \| "baseline" \| "stretch" \| "inherit"` | | Alignment of the items across cross axis. Defaults to `center` when `flow` is set to `row` or `row-reverse`. | | | `wrap` | `"wrap" \| "nowrap" \| "revert" \| "wrap-reverse"` | | Control content wrapping. | | | `gap` | `SpacingToken` | `"spacingM"` | Spacing between items. | | #### FlexItem In addition to the props below, you can pass [Box props](/components/layout/box#api-reference) to control the spacing. | Name | Type | Default | Description | Required | | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | | `as` | `keyof JSX.IntrinsicElements \| React.ComponentType` | `div` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node. For more details, read our [Composition](/get-started/composition#polymorphism) guide. | | | `css` | `StitchesCss` | | Apply styles directly to a component in a similar way how you would define inline styles. Wave uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. | | | `flex` | `"initial" \| "auto" \| "1" \| "none"` | | Control how flex item both grows and shrinks. | | | `grow` | `"0" \| "1"` | | Control how flex item grows. | | | `shrink` | `"0" \| "1"` | | Control how flex item shrinks. | | | `crossSelf` | `"auto" \| "start" \| "center" \| "end" \| "baseline" \| "stretch"` | | Override default (or the one specified by `cross` property on `Flex`) alignment across cross axis for the individual flex item. | | | `order` | `"first" \| "last" \| "none" \| "1" \| "2" \| "3" \| "4" \| "5" \| "6" \| "7" \| "8" \| "9" \| "10" \| "11" \| "12"` | | Control the order in which `FlexItem` appears in the `Flex` container. | | | `shrinkPastContentSize` | `boolean` | | When `true`, allows the flex item to be smaller than the size of its content. | | ## Grid A primitive for creating fluid, nestable grid layouts. ### Import ```js import { Grid, GridItem } from '@volue/wave-react'; ``` - `Grid`: The main grid wrapper defining the shape of the grid. - `GridItem`: Used as a child of `Grid` to control the span and start positions within the grid. ### Background **Grid** creates organized and consistent layouts, by providing a standard for positioning elements. Within a `Grid` container, `GridItem`s can be placed and aligned along a series of columns and rows via specific props. The **Grid** defaults to 12 columns scale, but you can manually adapt to different breakpoints by setting number of columns specific to each breakpoint. Pretty much all of the props available on `Grid` and `GridItem` are responsive, meaning they accept either a single value or an object that maps values to [breakpoints defined in Wave](/tokens/breakpoints). The consumer of the component is in control over how elements are laid out on the grid under different conditions, which offers huge flexibility. [See Breakpoints page](/tokens/breakpoints) to get an overview of the available breakpoints in Wave. **Grid** is an abstraction over [CSS Grid Layout Module](https://www.w3.org/TR/2020/CRD-css-grid-1-20201218/). ### Examples #### Default configuration Place items in a grid container and each cell will align to a column. By default each column will have an equal share of space available in the grid container and you can have up to 12 columns. Any cells that do not fit on a single row will wrap to a new row. The grid adds new rows as it grows and there is no limit. ```jsx {Array.from(Array(24)).map((_, i) => ( {i + 1} ))} ``` #### Customizing columns Large column count comes in handy when you want some finer control of things inside the grid, but for simple layouts you may want to customize the number of columns. ```jsx ``` ##### Responsive At different breakpoints, you may want different column counts. The `columns` prop is responsive. For example, if you wanted a single column on mobile and three columns from larger screens upwards: ```jsx ``` #### Specifying the rows By default there are no explicit rows; instead rows are auto-generated as items are added. There are however some cases where you do want to be specific about the number of rows. Grid component supports up to 6 explicit rows. In the example below the flow of the grid items is set to `column`, as opposed to the default `row`. Grid's `rows` are explicitly defined and `columns` are set to `none` to declare no explicit columns. This results in grid items flowing down column by column, adding new columns if needed. ```jsx {Array.from(Array(9)).map((_, i) => ( {i + 1} ))} ``` #### Spanning columns/rows In some layouts, you may need certain grid items to span specific amount of columns and rows instead of an even distribution. ##### Columns Pass the `colSpan` prop to the `GridItem` component to span across columns. ```jsx 1 2 3 4 ``` ##### Rows Pass the `rowSpan` prop to the `GridItem` component to span across rows. ```jsx 1 2 3 4 5 ``` ##### Responsive Props for controlling spanning are responsive. You can specify how many grid columns an item should stretch across per breakpoint. ```jsx ``` #### Starting and ending lines Items in the grid can be instructed to start or end at the _nth_ grid line. Note that CSS grid lines start at 1, not 0, so a full-width item in a 6-column grid would start at line 1 and end at line 7. ##### Column axis To position grid items along the horizontal column axis, `colStart` and `colEnd` properties. These can also be combined with the `colSpan` prop to span a specific number of columns. ```jsx ``` ##### Row axis To position grid items along the row axis, use `rowStart` and `rowEnd` props. These can also be combined with the `rowSpan` prop to span a specific number of rows. ```jsx ``` ##### Responsive If you need to customize the placement of an item at a specific breakpoint, the `GridItem` props are responsive. ```jsx ``` In the example below sidebar is positioned specifically, giving it a different visual order to the source code. ```jsx Main content Sidebar ``` #### White space ##### Uniform gap size Use `gap` property to change the white space between both rows and columns in a grid layout using [Wave's standard white space scale](/tokens/white-space). When no explicit `gap` is provided, the white space between the items defaults to `spacingM`. ```jsx ``` ##### Customizing row and column gaps independently Use `rowGap` and `columnGap` to change the gap between rows and columns independently. ```jsx {Array.from(Array(6)).map((_, i) => ( ))} ``` ##### Gapless In case you want to remove the gaps altogether, set the `gap` prop to `none`. ```jsx ``` #### Sizing in the implicit grid If there are more grid items than cells in the grid or when a grid item is positioned outside of the explicit grid (defined by `columns` or `rows`), the grid container automatically generates implicit grid tracks by adding new grid lines. The default for tracks in the implicit grid is for them to be auto-sized, meaning they will expand to contain the content you place into them. ##### Sizing implicit rows Use `gridAutoRows` prop to define sizing of implicitly-created grid rows. In the example below all rows have the same size (the tallest item in the grid sets the height for all rows). ```jsx ``` ##### Sizing implicit columns Use `gridAutoColumns` prop to define sizing of implicitly-created grid columns. In the example below `flow` is changed to `column` and each columns size is as small as possible without causing the content to overflow. ```jsx ``` #### Alignment options ##### Grid items alignment `justifyItems` property defines the alignment of grid items along the inline (row) axis. In the example below we are aligning grid items to be flush with the start edge of their cell (by default they would have been stretched to fill it). ```jsx ``` `alignItems` property defines the alignment of grid items along the block (column) axis. In the example below grid items of varying height have been centered vertically. ```jsx ``` ##### Grid alignment Sometimes the total size of your grid might be less than the size of its grid container. In this case you can set the alignment of the grid within the grid container. `justifyContent` property defines the alignment of the grid along the inline (row) axis. ```jsx ``` `alignContent` property defines the alignment of the grid along the block (column) axis. ```jsx ``` ##### Individual grid items alignment Alignment values can be set on individual grid items. `GridItem` exposes `align` and `justify` properties to provide granular control over the alignment of a single item inside the grid. In the example below grid items are aligned to the end edge of their columns, except the middle one which is instructed to be placed in the center. ```jsx ``` #### Nesting Let's look at a common use case where we need to layout a view with a sidebar and a grid within the content area. ```jsx

Contact us

We can't wait to hear from you. Feel free to get in touch with us.
Happy ST
000-111-222
First name Last name Email Address Topic Write your message