This is a Technology Sample you can rely on to build your own Design System, based on React and a System UI theme.
Disclaimer: Technology Samples aren't comprehensive Design Systems but showcases a given technology so you free to build you own solution upon it.
This tech sample uses React and JSX to implement its components with TypeScript. The Tokens are following the System UI theme specification, and are consumed in two flavors: Theme UI and styled-components.
The Tokens are separated in different components:
typography
: fonts definitionscolors
: colors and variantsspace
: relative and absolute spacessizes
: screensize breakpointsshadows
: inset and outset shadowsradii
: border radiusborder
: borders definitionsz-index
: z-axe indices
The System UI tokens specification allows you to define scales (like font-sizes
, radius
, etc) in arrays. You can also refer to previously declared values as aliases.
Your tokens
should be organized by following the key reference in the specification:
Theme Key | CSS Properties |
---|---|
space | margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left, grid-gap, grid-column-gap, grid-row-gap |
fontSizes | font-size |
colors | color, background-color, border-color |
fonts | font-family |
fontWeights | font-weight |
lineHeights | line-height |
letterSpacings | letter-spacing |
sizes | width, height, min-width, max-width, min-height, max-height |
borders | border, border-top, border-right, border-bottom, border-left |
borderWidths | border-width |
borderStyles | border-style |
radii | border-radius |
shadows | box-shadow, text-shadow |
zIndices | z-index |
transitions | transition |
All tokens are declared in dedicated *.ts
files in each tokens' components. They're then all exposed by the all/index.ts
component file in a theme
constant.
Your theme tokens can be imported anywhere with
import { theme } from '~/all';
This tech sample exposes components in two flavor. They all use the same theme tokens imported as above, so your React components and your theme are not hard-linked together, and you can rely on the theme abstraction you're the most comfortable with.
Both Theme UI and styled-components exposes a <ThemeProvider />
JSX wrapper that take as theme argument a system-ui theme tokens definition:
<ThemeProvider theme={theme}>
<!-- Your component(s) here -->
</ThemeProvider>
To avoid the need of loading the <ThemeProvider />
decorator in each components, we have overridden the stories and doc layouts in the tui-utils
component.
export const Layout = (props) => (
<ThemeProvider theme={theme}>
<MdxLayout {...props} />
</ThemeProvider>
);
In the tui-utils
component, the global theme as well as all components variations are loaded and merged in a common theme definition in the variants.ts
file. This definition is then used by the <ThemeProvider />
that decorates the different layouts.
To add new theme-ui based components, you have to create a component with two files: your component itself, and a variants.ts
file that declares the theme-ui compatible components definitions.
Your component's variants.ts
file have to be loaded in the tui-utils/variants.ts
file to be used by the wrapped theme.
On the contrary of Theme UI, styled-component doesn't declares variations at theme level, but let you customize your components' styles directly by using the theme definitions:
import styled from 'styled-components';
const StyledButton = styled.button(
({ theme, primary = true, secondary, disabled = false, loading = false }) => {
return {
'font-size': theme.fontSizes[2],
padding: `${theme.space[2]} ${theme.space[3]}`,
};
}
);
export const Button = () => <StyledButton />;
To add new styled-components component, create a component that import the styled-components core utils:
import * as React from 'react';
import styled from 'styled-components';
import { ThemeContext } from 'styled-components';
export const MyComponent = () => {
const theme = React.useContext(ThemeContext);
return (
// Your component here
);
};
Stories are written in Storybook's Component Story Format.
You can defined multiple stories for your components to visualize their variations:
import { Button } from '../index';
import { layout } from '~/tui-utils';
export default layout;
export const primary = () => <Button variant="primary">Primary</Button>;
export const secondary = () => <Button variant="secondary">Secondary</Button>;
export const disabled = () => <Button disabled>Disabled</Button>;
export const secondary_disabled = () => (
<Button variant="secondary" disabled>
Disabled
</Button>
);
Stories for the components are located in their stories/
folder.
Documentation pages are decorated by a React layout using the @divriots/dockit-react helpers. See the layout
component.
Each component embed its own documentation in its doc/
folder. You can use any web format for your documentation but we recommend you to write it with the mdx format, allowing you to embed your components live in the documentation.