BlogProjectsVideosMusic
|
My­Tailwind­Config
the wind beneath my wings
2025/03/23

Well I think it's important to mention that this is obviously going to be very simple and of my personal preference. A starting point, a diving board, a ladder to the sky. You don't have to follow this religiously.

The most important and time-consuming and stress-inducing thing in my design workflow is figuring out which colours to use. That and fonts. Fonts are scary. Fortunately with this handy configuration, fonts and colours are really easy to change at the drop of a hat - or an indecisive client.

Probably going to be easiest if I just drop my whole tailwind.config.ts file and then talk about each part after...

1import type { Config } from "tailwindcss"; 2const colors = require("tailwindcss/colors"); 3 4const config: Config = { 5 content: [ 6 "./**/*.{js,ts,jsx,tsx,html}", 7 ], 8 darkMode: "selector", 9 theme: { 10 fontFamily: { 11 sans: ["var(--font-sans)", "sans"], 12 serif: ["var(--font-serif)", "sans-serif"], 13 mono: ["var(--font-mono)", "monospace"], 14 }, 15 extend: { 16 colors: { 17 primary: colors.zinc, 18 accent: colors.emerald, 19 }, 20 spacing: { 21 "screen-xs": "480px", 22 "screen-sm": "640px", 23 "screen-md": "768px", 24 "screen-lg": "1024px", 25 }, 26 }, 27 }, 28}; 29export default config;

Here she is, my pride and joy.


Colors

Skipping fonts for the moment - we will come back, don't fret. The colors are perhaps the easiest little bit of life-saving config ever. TailwindCSS, by default, provides a vast, beautiful color palette out of the box and there's almost too many options to choose from.

Importing Tailwind's colors at the top of the file, like so:

1const colors = require("tailwindcss/colors");

allows for entire palettes to be additionally assigned to new names. This can be fine-tuned to single swatches of color being named something specific, such as info, warning, and error colors.

My signature move is assigning a palette to each represent a primary and an accent color. The primary is for backgrounds and text, such as the stuff you're reading now. Whereas the accent color is for titles, headings, icons, things that we want to draw the eye. The beauty of assigning a whole palette in the config, is that they are so easy to change. TailwindCSS has curated the palettes to all work together nicely - for the most part - so playing around with color combos is as simple as changing what the primary and accent palettes point to and watching your whole app/site adjust automatically.

Extending the colors in this way means that the primary and accent palettes can still be accessed in the Tailwind convention of bg-primary-800 or text-accent-400.

It also allows for a very easy dark mode transition. If you note the darkMode: 'selector' line in the config, this means that somewhere up the rendering tree a parent node just needs to contain the Tailwind class "dark" and then every single child, and child's child, and child's child's child, etc., will use the dark mode directive. This directive can be set on components like so:

1<div className="text-primary-800 dark:text-primary-100" />`

This allows for dark mode styles to be inline with light mode. That's pretty much all she wrote about colours; you can add custom palettes and additional stuff, but I've found that limiting myself to two colors allows for more intentional design decisions down the track.


Fonts

Fonts can be done differently dependeding on which framework (if any) you're using with Tailwind. Like most, Next.js is my framework of choice for most simple, interactive, frontend + backend projects. Fortunately, the people at Next.js are very smart and conscientious and they have already built-in the Google Fonts library into the framework.

This makes importing the fonts into reusable Tailwind classes very simple indeed, but first requires a little bit of config in the root layout.ts file.

At the moment, I'm using just 3 fonts: a serif, a sans-serif, and a monospaced for the code blocks like this one. namely Noto-Serif, Raleway and Source-Code-Pro, respectively.

In your root layout.ts file, import your desired fonts from the 'next/font/google' package. Inside each definition, the variable option exports the font into the stated CSS variable, to be picked up in the Tailwind config.

1import { Source_Code_Pro, Raleway, Noto_Serif } from "next/font/google"; 2 3const serif = Noto_Serif({ 4 subsets: ["latin"], 5 variable: "--font-serif", 6}); 7 8const sans = Raleway({ 9 subsets: ["latin"], 10 variable: "--font-sans", 11}); 12 13const mono = Source_Code_Pro({ 14 subsets: ["latin"], 15 variable: "--font-mono", 16});

Looking back up to the tailwind.config.ts these newly defined CSS variables can be linked to TailwindCSS with the following

1fontFamily: { 2 sans: ["var(--font-sans)", "sans"], 3 serif: ["var(--font-serif)", "sans-serif"], 4 mono: ["var(--font-mono)", "monospace"], 5}

After this, the fonts can be accessed as you would any other font option.

1<span className="font-sans text-sm text-primary-800">...</span>

This wraps up the config for Next.js, but in other occasions when I use Vite you have to do it the old fashioned way... All the way back to the root of your application. Perhaps it's an index.html or an App.jsx or an index.tsx or something like that. We've gotta go back to using the <link /> tags. Some big ugly jumble of URLs like this.

1<link rel="preconnect" href="https://fonts.googleapis.com"> 2<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 3<link href="https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,100..900;1,100..900&family=Raleway:wght@100..900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap" rel="stylesheet">

Adding the above to the <head>...</head> tags of whatever the root file is, then going back to the TailwindCSS config file and creating the references:

1fontFamily: { 2 sans: ["Raleway", "sans"], 3 serif: ["Noto Serif", "sans-serif"], 4 mono: ["Source Code Pro", "monospace"], 5}

I much prefer the Next.js way of doing it; but as soon as the browser caches the font the first time, I have no further complaints about the embed URLs.


Spacing

If you're not doing mobile-first web-development in 2025 then you're doing it wrong, some say. I, like most, have a love-hate relationship with mobile web-development mainly due to the very limited screen real estate. Tailwind provides a great way to encourage this mobile-first intiative with style breakpoints.

1<div className="text-sm lg:text-lg">Welcome!</div>

The lg: prefix means that for screen-sizes that are "large" or greater, override the default property - text size in this instance. But what Tailwind doesn't provide is these breakpoints as ready-to-use sizes for html objects.

If I wanted the width of the element to fill the screen up until a certain screen size I would have to do some trickery, or hardcode a value. I've added the above breakpoint sizes as values to be used as widths and heights for all elements.

1<div className="w-full max-w-screen-lg">Welcome!</div>

I've achieved this result with the following configuration:

1spacing: { 2 "screen-xs": "480px", 3 "screen-sm": "640px", 4 "screen-md": "768px", 5 "screen-lg": "1024px", 6}

These values are not plucked from thin air, but match the breakpoints exactly.


This pretty much covers it, nothing too fancy, nothing too personal, nothing too custom. Just quality of life adjustments that can be added to any project to slightly increase the ease of working with the already fantastic TailwindCSS.

Outside of the configuration file, I'd strongly recommend plugins like prettier-plugin-tailwindcss that sorts the Tailwind classes into a predictable order, and additionally a TailwindCSS Intellisense plugin for a helpful autocomplete and so you know exactly what styles are being applied in a Tailwind class.