Design System Foundations Using Tailwind


We can either extend or completely reset the colors. Let's reset the colors. The brand Color of is #007dfc . HSL is easy to understand. The brand color translates to ‘hsl(210, 100%, 49%)’ in HSL.

  • Saturation: 100%
  • Lightness: 49%
theme: {
colors: {
primary: {
50: 'hsl(210, 100%, 97%)',
100: 'hsl(210, 100%, 91%)',
200: 'hsl(210, 100%, 80%)',
300: 'hsl(210, 100%, 70%)',
400: 'hsl(210, 100%, 60%)',
500: 'hsl(210, 100%, 49%)',
600: 'hsl(210, 100%, 39%)',
700: 'hsl(210, 100%, 28%)',
800: 'hsl(210, 100%, 16%)',
900: 'hsl(210, 100%, 10%)',
extend: {},

It is gray. But “primarily” tinted!

The primary color is for cueing the user about the most important thing to notice on a page. But gray is the most used color in any application.

Using HSL format helps us easily come up with related colors with great precision.

Gray can be achieved by reducing the saturation to 0% at any hue. But we generate our gray like below to match our primary color.

  • Reduce saturation from 100% to around 12%.
gray: {
50: 'hsl(210, 12%, 97%)',
100: 'hsl(210, 12%, 91%)',
200: 'hsl(210, 12%, 80%)',
300: 'hsl(210, 12%, 70%)',
400: 'hsl(210, 12%, 60%)',
500: 'hsl(210, 12%, 49%)',
600: 'hsl(210, 12%, 39%)',
700: 'hsl(210, 12%, 28%)',
800: 'hsl(210, 12%, 16%)',
900: 'hsl(210, 12%, 10%)',
  • Green: #00CC66 or hsl(150, 100%, 40%)


Font size

We reset the tailwind’s type scale with the below.

fontSize: {
// Body copy
'xs': ['.75rem', '1rem'],
'sm': ['.875rem', '1rem'],
'base': ['1rem', '1.5rem'],
'lg': ['1.125rem', '1.5rem'],
// Headings
'xl': ['1.5rem', '2rem'],
'2xl': ['2rem', '2.5rem'],
// Display
'3xl': ['5rem', '6rem'],
'4xl': ['10rem', '10rem'],

Body copy

  • text-xs is mostly used for badges. If we go with full uppercase with relaxed letter spacing, an xslooks good compared to sm or base.
  • text-sm is helpful for the text in product cards.
  • text-base is the base size that applies by default. We picked 16px as the base for this e-commerce product. But remember the body text you are currently reading is 21px (in desktop mode).
  • text-lg can be used for callouts, descriptions, etc. This can be used as a heading too with enough font-weight using h3.


  • text-xl is our h2.
  • text-2xl is our h1.

Display Headings

  • text-3xl and text-4xl are used in rare situations where we need obnoxiously huge texts.

Font weight

The text size does not have to dictate hierarchy. Our limited headings text-xl and text-2xl can be emphasized by providing a thicker font-weight.

Letter Spacing

letter-spacing demo

The bigger the text is, the tighter the letter-spacing should be.

Line height

Line height can be fixed or relative. We have already given suitable line heights for each text size.

lineHeight: {
'no-gap': '.8',
'extra-tight': '.9',
'none': ' 1',
'tight': ' 1.25',
'snug': ' 1.375',
'normal': ' 1.5',
'relaxed': ' 1.625',
'loose': ' 2',
line heights

The smaller the text is the larger the line height should be.


Tailwind CSS comes with a good range of shadows with the classes shadow-sm -> shadow-2xl. Let’s use them as it is.


Light source

The light source is assumed to be behind the top of the user’s head making the shadows fall below the object.

Foreground color

Making the default background color a shade darker will get de-emphasized automatically.

Dark mode

In dark mode, the shadows almost won't work. The difference in lightness between the foreground vs background gives a sense that the lighter items are closer to the user.

The lighter items look closer.

Also, notice how the darker card shadow-inner looks like a punched-out hole even though the inner shadow is almost nonexistent.


In the text size section, we did a deliberate effort to make the line-heights divisible by 8px.

spacing: {
0: '0rem',
0.5: '0.125rem',
1: '.25rem',
2: '.5rem',
3: '1rem',
4: '1.5rem',
5: '2rem',
6: '3rem',
7: '4rem',
8: '5rem',
9: '6rem',
10: '8rem',
11: '10rem',
12: '12rem',
13: '16rem',
14: '20rem',
15: '24rem',
16: '32rem',


I copied the necessary SVGs from hero icons. I exported them from an index.

  • Icons can become inconsistent if we start copying SVGs from multiple sources.


Tailwind comes with zIndex classes for values 0,10,20,30,40,and 50. I prefer having one value behind 0.

extend: {
zIndex: {
'-10': -10,

Flexbox and Grid

The utility classes tailwind provides for flexbox and grid are going to be responsible for our layout design throughout our application.

flexbox and grid


Let's add line clamp and aspect ratio as add-ons.

// Install
npm i @tailwindcss/aspect-ratio @tailwindcss/line-clamp
// Import in tailwind.config.js
const lineClamp = require('@tailwindcss/line-clamp')
const aspectRatio = require('@tailwindcss/aspect-ratio')
// Add this in module.exports.
plugins: [lineClamp, aspectRatio]


TailwindCSS JIT brings immense benefits to the developer experience. Have look at the official documentation for details.

  • Add TAILWIND_MODE=watch in the start scripts.
"start": "TAILWIND_MODE=watch craco start",
"storybook": "TAILWIND_MODE=watch start-storybook -p 6006 -s public",

The config file

After all the work, taliwind.config.js will become like below.


We have created the foundation for our design system. Next up we will be creating base components like accordions, avatars, buttons etc.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Karthick Ragavendran

Karthick Ragavendran

Fullstack engineer @ | React, Typescript, Redux, JavaScript, UI, Storybook, CSS, UX, Cypress, CI/CD.