-
-
Notifications
You must be signed in to change notification settings - Fork 251
Using Design System
Welcome to the trezor-suite wiki!
DS = design system
-
Deployed
-
Local run
-
yarn nx run @trezor/components:storybook
- runs on http://localhost:9003/
-
yarn nx run @trezor/product-components:storybook
- runs on http://localhost:9004/
-
- 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
- Design primitives (a.k.a. LEGO building blocks) from which the rest of the application is composed.
- More complex
product-components
are built from these 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/components
and@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>
// BEST ✅ ✅
import { spacings } from '@trezor/theme';
...
<Button margin={{ left: spacings.xs }}>Hey!</Button>
- Do not add new components to
@trezor/components
without approval in the [@suite_usability_feedback](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) Slack channel, and we will help you
- For layout, we use components like
Row
,Column
,Table
,Grid
, andList
- For spacing, we use the
gap
prop - Layout components support various props from
frameProps
, typicallymargin
,width
, orheight
. Typically you can find allowed props in storybook or types. - Where possible, we use semantic HTML elements (e.g.,
section
,header
) for custom components
// 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: spacings.xs, bottom: spacings.xxs }}>
<div>Hola</div>
<div>Hey</div>
</Row>
There are many legacy tokens in the app. We are continuously refactoring them but it takes time. In the new functionality, we try to avoid them if possible. You can typically recognize legacy component with following 3 characteristics:
-
UPPER CASE syntax
- Example:
variables.FONT_SIZE.TINY
- Example:
-
it has
legacy
in the name- Example
theme.legacy.TYPE_LIGHT_GREY
- Example
-
IDE shows it’s deprecated (usually it’s strike-through)
- Example
// BAD ❌
font-size: ${variables.FONT_SIZE.TINY};
color: ${({ theme }) => theme.legacy.TYPE_LIGHT_GREY};
// GOOD ✅
${typography.label};
color: ${({ theme }) => theme.textSubdued};
- For most DS components where it makes sense, it's possible to set a color. Primarily, we always use the
variant
prop, 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, thecolor
prop can be used, though it is generally considered deprecated. - The variants provide basic color settings:
primary, secondary, tertiary, info, warning, destructive
.
- 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 thecolor
prop). -
~~color~~
: (deprecated) allows setting a specific text color. Cannot be used withvariant
. Instead, thevariant
property should always be used. -
typographyStyle
: basically style from list above -
textWrap
: 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>
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
spacings
orspacingsPx
.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).
- 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.
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>
- 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)
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