
In the previous post we demonstrated how the design library was made including:
Now it's time to implement them in code. We followed the sequence of how the designs were made, starting with variables.
For colours, we created a separate colors.css file in @repo/ui, storing the colours as root variables in RGB format, imported them in index.css, and extended the theme in tailwind-preset.ts with these colours, referencing them via their variable names.
For the non-opaque colours we left out the alpha value to let tailwind set it.
Instead of explicit pixel values, we work in rems (reference to root element's font size - html), and used 16px as the root font size. We had to convert the pixel values specified in Figma to rems (for example xl font size is 32px, which translates to 2rem - 32 / 16).
The changes can be found here: GitHub link
We added the react-icons package that contains the ionicons package which we use in the designs.
Because it inserts the icons as svg tags instead of img, we can freely customise the colour and size of the icons.
Compare the changes on GitHub here: GitHub link
First, we created the tailwind styles for each typography element:
specifying their:
fontSize variables)We created a low-level Text component that is highly customizable. It supports a custom className and accepts $variant and $bold props for flexibility.
We also created each typography element as individual components, using Text, and specifying their respective $variants.
Check the code: GitHub link
To match the design system, we structured button styles based on:
Each of these was defined in a way that allows easy reuse and modification, to make sure buttons are consistent.
Instead of styling each button manually, we created a base component (ButtonBase) that:
The main Button component extends this by adding:
label prop for text-based buttons wrapped in BodyRegular.$size and $variant props to match designs.IconLeft and IconRight props to easily include icons.For even cleaner usage, we also defined preconfigured buttons:
<PrimaryButton /><SecondaryButton /><OutlineButton /><GhostButton />These provide an easy way to use the correct styles without repeating props, keeping the UI implementation simple.
To ensure buttons work as expected, we:
See the changes on GitHub: GitHub link
Similarly to buttons, we styled inputs based on the design system with:
We structured the input component into reusable parts:
InputBase – Core input styling.InputWrapper – Handles labels, notes, and errors.InputLabel, InputNote, InputError – Text elements.The Input component combines these elements, and alongside with native input props, it supports additional props to match designs:
$variant and $size props for quick customization.label , note , and error (can be hidden with hideError ).IconLeft and IconRight props to easily include icons.We also wrote unit tests to validate behaviour and added Storybook stories to preview all variations.
See the changes on GitHub: GitHub link
Checkbox variations are based on:
Since native checkboxes are difficult to style, we created a fake checkbox and linked it to the actual input via label. The checked state is handled through conditional styles.
We reused informational components from Input, including:
InputNote – Displays additional information.InputError – Shows error messages when validation fails.Custom properties follow the same structure as Input:
$size to match the design system.label, note, and error (with hideError to disable error messages).As standard, we wrote unit tests and added Storybook stories to verify interactions, states, and accessibility.
This is how it looks like in code: GitHub link
As seen in the code, we avoided implementing controlled inputs and instead forwarded refs . The reason for this is to leverage native functionality as much as possible—uncontrolled inputs are more performant since they don't rely on React state or cause unnecessary re-renders.
(We will remove forwardRef when upgrading to React 19, as it has been deprecated.)
The modal consists of two components:
Overlay – A full-screen layer with a semi-transparent black background that blocks interaction with content behind it.Modal – A component that appears in front of the overlay, drawing focus to user interactions or important content.The Modal component is flexible in terms of content, allowing any children to be passed inside. It includes predefined styles and optional elements:
title – An optional heading at the top.hideCloseButton.The modal closes when the overlay is clicked or when the close button is pressed.
We wrote unit tests, and stories for the modal. Check the code here: GitHub link
Summary of all changes in the code can be found here: GitHub link.
Tasks and subtasks for this setup are listed on our ClickUp board.
Full designs can be found in the Figma file:
All key project documentation is available in our ClickUp wiki.
We will use these components to build the application's screens, aligning them with the user stories and design specifications.
In the meantime, design will be working on the authentication screens:
Here's how our timeline look like now: