Welcome to the trezor-suite wiki!
DS = design system
Storybooks
Desktop atom components
- basic "lego" blocks / atoms
- Suite agnostic
yarn nx run @trezor/components:storybook(runs on http://localhost:9003/)- Deployed on: https://dev.suite.sldev.cz/components/develop/
Desktop product-components
- usually more complex product related components composed by desktop
- Suite related
yarn nx run @trezor/product-components:storybook(runs on http://localhost:9004/)- Deployed on: https://dev.suite.sldev.cz/product-components/develop/
Mobile components
Components
@trezor/product-components
- A package with UI components that are product-oriented and can be shared across
Suite,Connect, etc. - In their implementation, they usually use simpler primitives from
@trezor/components
@trezor/components
- Design primitives (a.k.a. LEGO building blocks) from which the rest of the application is composed.
- More complex
product-componentsare built from these components.
Using components
Don’t override components
- We do not override components from
@trezor/components - If necessary, we wrap them with our own wrapper component
- If it makes sense, we request a modification or extension of the DS component in [@suite_usability_feedback](https://satoshilabs.slack.com/archives/C07NNMUBJFN)
- We have custom eslint rule that guards not overring components from
@trezor/componentsand@trezor/product-components. Please neve use eslint ignore for this rule even though we have many of these suppressions in the app.
// BAD ❌
const StyledButton = styled(Button)`
margin-left: 8px;
`;
...
<StyledButton>Hey!</StyledButton>
// SEMI-GOOD 🟠
// This solution is 100% good in the case when component doesn't allow you to change desired property (which is not case of `margin-left`)
const StyledButton = styled.div`
margin-left: 8px;
`;
...
<Wrapper>
<Button>Hey!</Button>
</Wrapper>
// GOOD ✅
<Button margin={{ left: 8 }}>Hey!</Button>
### Adding new components
- Do not add new components to `@trezor/components` without approval in the [[@suite_usability_feedback](https://satoshilabs.slack.com/archives/C07NNMUBJFN)](https://satoshilabs.slack.com/archives/C07NNMUBJFN) Slack channel
- If you need a new component, let us know in [[@suite_usability_feedback](https://satoshilabs.slack.com/archives/C07NNMUBJFN)](https://satoshilabs.slack.com/archives/C07NNMUBJFN) Slack channel, and we will help you
## Layout
- For layout, we use components like `Row`, `Column`, `Table`, `Grid`, and `List`
- For spacing, we use the `gap` prop
- Layout components support various props from `frameProps`, typically `margin`, `width`, or `height` . Typically you can find allowed props in storybook or types.
- Where possible, we use semantic HTML elements (e.g., `section`, `header`) for custom components
```jsx
// BAD ❌
const Row = styled.div`
display: flex;
flex-direction: row;
align-items: space-between;
margin-top: 8px;
margin-bottom: 4px;
`;
...
<Row>
<div>Hola</div>
<div>Hey</div>
</Row>
// GOOD ✅
import { Row } from '@trezor/components';
...
<Row alignItems="space-between" margin={{ top: 8, bottom: 4 }}>
<div>Hola</div>
<div>Hey</div>
</Row>
Design tokens / CSS
Component Colors via variant
- For most DS components where it makes sense, it's possible to set a color. Primarily, we always use the
variantprop, which sets the color according to predefined design variants. Sometimes it might be necessary to use a different color that isn't defined in the variants. In such cases, thecolorprop can be used, though it is generally considered deprecated. - The variants provide basic color settings:
primary, secondary, tertiary, info, warning, destructive.
Typography
- For all text elements, it is possible to set different typography. In the application, we have a predefined list of all used combinations, and we always use them in these combinations. You can choose from the following options:
// packages/theme/src/typography.ts
const typographyStylesBase = {
titleLarge: {
fontSize: 48,
lineHeight: 53,
fontWeight: fontWeights.medium,
letterSpacing: 0.4,
},
titleMedium: {
fontSize: 34,
lineHeight: 37,
fontWeight: fontWeights.medium,
letterSpacing: 0.4,
},
titleSmall: {
fontSize: 22,
lineHeight: 32,
fontWeight: fontWeights.medium,
letterSpacing: -0.3,
},
highlight: {
fontSize: 16,
lineHeight: 24,
fontWeight: fontWeights.semiBold,
letterSpacing: -0.4,
},
body: {
fontSize: 16,
lineHeight: 24,
fontWeight: fontWeights.medium,
letterSpacing: -0.4,
},
callout: {
fontSize: 14,
lineHeight: 20,
fontWeight: fontWeights.semiBold,
letterSpacing: -0.3,
},
hint: {
fontSize: 14,
lineHeight: 20,
fontWeight: fontWeights.medium,
letterSpacing: -0.3,
},
label: {
fontSize: 12,
lineHeight: 18,
fontWeight: fontWeights.medium,
letterSpacing: -0.1,
},
}
For all text, we use the Text or Paragraph components. Paragraph is a block-level text element and internally uses the Text component. These components also allow setting common font properties:
variant: Sets the text color based on the variant (cannot be used together with thecolorprop).~~color~~: (deprecated) allows setting a specific text color. Cannot be used withvariant. Instead, thevariantproperty should always be used.typographyStyle: basically style from list abovetextWrap: you can set how text should be wrapped, for example for not having orphans in the last line
Example:
// BAD: custom typography ❌
const CustomText = styled.div`
font-size: 14px;
`
const CustomParagraph = styled.p`
font-size: 14px;
`
<CustomText>I love Solana</CustomText>
<CustomParagraph>I love Bitcoin even more</CustomParagraph>
// BAD: using deprecated tokens ❌
const CustomText = styled.div`
font-size: ${variables.FONT_SIZE.TINY};
`
const CustomParagraph = styled.p`
font-size: ${variables.FONT_SIZE.TINY};
`
<CustomText>I love Solana</CustomText>
<CustomParagraph>I love Bitcoin even more</CustomParagraph>
// GOOD ✅
<Text typographyStyle="callout">I love Solana</Text>
<Paragraph typographyStyle="callout">I love Bitcoin even more</Paragraph>
Using design tokens
We try to use design tokens from @trezor/theme as much as possible. It improves consistency in the app and it’s also easier to refactor. We don’t allow non-standard values.
-
Spacings
For all sizes in general (especially margins and paddings) we always use predefined sizes from
spacingsorspacingsPx.Example:
// // BAD ❌ // // using in CSS ❌ const CustomComponent = styled.div` padding: 12px; ` // Not using spacingsPx ❌ const CustomComponent = styled.div` padding: ${spacings.md}px; ` // Using in prop ❌ <Row margin={{ top: 123 }} gap={123}> ... </Row> // // GOOD ✅ // import { spacings, spacingsPx } from '@trezor/theme'; // using in CSS ✅ const CustomComponent = styled.div` padding: ${spacingsPx.md}; ` // Using in prop ✅ <Row margin={{ top: spacings.md }} gap={spacings.md}> ... </Row> -
Borders
We use predefined border radii and widths. You can find current options here
packages/theme/src/borders.ts.Example of using borders:
// BAD: use incorrect values and without tokens ❌ const Box = styled.div` border-radius: 6px; border: solid 0.5px red; ` // BAD: use correct values, but without tokens ❌ const Box = styled.div` border-radius: 8px; border: solid 1px red; ` // GOOD ✅ import { borders } from '@trezor/theme'; ... const Box = styled.div` border-radius: ${borders.radii.xs}; border: solid ${borders.widths.small} red; ` -
Z-indices
-
boxShadows
-
Icons
We should use only icons from our iconset. Ideally we shouldn’t use icons that are marked as deprecated. Iconset can be found [here](https://dev.suite.sldev.cz/components/develop/?path=/story/icons--all-icons).
Use $ for parameters in styled-components
- more info here
- odkaz na figmu s barvama
Desktop app shares color tokens with Mobile app. This means we can’t simply change them without being aligned together. In case we need a new color we don’t add it to the theme but ideally we should ask in the Slack channel [suite_usability_feedback](https://satoshilabs.slack.com/archives/C07NNMUBJFN)) why it’s missing.
Elevations
In a design system, elevation refers to the visual hierarchy created by applying shadows or layering effects to elements, giving them a sense of depth and prominence. It helps to differentiate between components based on importance or interaction level, typically using predefined shadow styles or z-index values.
How to use elevation for background:
// BAD: using elevated color but not respecting current elevations ❌
const Container = styled.div`
background: ${({ theme })=> theme.backgroundSurfaceElevation0};
`;
// GOOD ✅
import { useElevation } from '@trezor/components';
import { mapElevationToBackground, Elevation } from '@trezor/theme';
// Improvement: `${({ theme, $elevation }) => mapElevationToBackground({ theme, $elevation })}` can be simplified to: `${mapElevationToBackground}`;
const Container = styled.div<{ $elevation: Elevation }>`
background: ${({ theme, $elevation })=>
mapElevationToBackground({ theme, $elevation })};
`;
const Component = () => {
const { elevation } = useElevation();
return (
<Container $elevation={elevation} />
)
}
It works the same also for border:
import { mapElevationToBorder } from '@trezor/theme';
...
border: solid 1px ${mapElevationToBorder};
You can rise or lower elevation with ElevationUp and ElevationDown components:
<Container>
<ElevationUp>
This context has higher elevation
</ElevationUp>
<ElevationDown>
This context has lower elevation
</ElevationDown>
</Container>
Code review
- screenshots nebo dobrý popis
- maintain PR without growing too big. Ideally less than 500 changed lines. Otherwise it’s really hard to go through it
- Add screenshots to your PR if it’s related to UI. Ideally two screenshots - before and after state and describe or draw if something is necessary to explain.
- přidat odkaz na figmu
- Ask for codereview here: [suite_usability_feedback](https://satoshilabs.slack.com/archives/C07NNMUBJFN)
FAQ
Who to ask
Design system questions:
- Jan Václavík (jan.vaclavik@satoshilabs.com)
- Adam Havel (adam.havel@satoshilabs.com)
Design questions:
- Ondřej Dostál (ondrej.dostal@satoshilabs.com)
- David Kotík (david.kotik@satoshilabs.com)
Product questions:
-
Jakub Hřebeňár (jakub.hrebenar@satoshilabs.com)
-
Slack channel or DM (Satoshi Labs only) [suite_usability_feedback](https://satoshilabs.slack.com/archives/C07NNMUBJFN) (feedback, request for update, help)
-
[Suite Foundation (Figma)](https://www.figma.com/design/Ix8nzlD0drtZzt231Pgml7/%5BSuite%5D-Foundations?node-id=2-1036&node-type=frame&t=bRBClFkfpwJjj0Aj-0)
-
[Suite Components (Figma)](https://www.figma.com/design/Y2E8dcdNYrSMGIVRjYFXKp/%5BSuite%5D-Components?node-id=18-8420&node-type=canvas&t=zapqgc70MFeSzAQp-0)
-
How to deal with media queries