Override Tailwind Typography with twin.macro

October 19, 2020

Typography is a key element on a web page containing a lot of content. It is also a wide topic covering font families, sizes, weights, line heights, spacing and so many other specs it can quickly become overwhelming to reach a satisfactory result.

As a Tailwind CSS enthusiast, I decided to give a try to the Tailwind Typography plugin during the redesign phase of my portfolio website. As the docs state, "Tailwind Typography adds a set of customizable prose classes that you can use to add beautiful typographic defaults to any [...] content."

I love when external solutions help you to save time on repetitive tasks while remaining flexible enough to be adjusted to your needs. My first few minutes with the plugin didn't necessary carry that feeling but I eventually found a somehow working solution.


First you'll need to install the plugin via Yarn/NPM (yarn add @tailwindcss/typography) and require it in your Tailwind config file

1// tailwind.config.js
2module.exports = {
3  theme: {
4    // ...
5  },
6  plugins: [
7    require('@tailwindcss/typography'),
8    // ...
9  ],

Job done! You can now use the prose class anywhere in your code. If you are curious, the plugin's default styles can be found here.

However I quickly realized some tweaks were needed to fit my liking as spaces, lists decoration, underlines etc were not matching the design in other parts of my site.


The documentation mentions customization is possible if you declare new rules for the default theme in your config file.

1// tailwind.config.js
2module.exports = {
3  theme: {
4    typography: {
5      default: {
6        css: {
7          color: '#333',
8          a: {
9            color: '#3182ce',
10            '&:hover': {
11              color: '#2c5282',
12            },
13          },
14        },
15      },
16    },
17  },
18  plugins: [
19    require('@tailwindcss/typography'),
20    // ...
21  ],

This works to some extent but still didn't provide the full flexibility I am used to. The styles you change here are still applied everywhere. Being able to override or disable the prose class based on your need seems to be a common request in the community and I don't doubt a solution will soon be available.

In the meantime, I found out that inlining styles with an !important attribute was powerful enough to override the prose class, which makes sense considering the hierarchy of specificity in CSS. Using !important isn't usually the best way to take but it is punctual enough for me to be fine with it.

However one issue remained: inline styles don't accept Tailwind classes, which I try to stick to as much as I can, for consistency reasons.

Twin.Macro to the rescue

Even though I use Tailwind a lot, I sometimes need to apply styles to inner elements I don't have access to. A typical use case is some markup you receive from a CMS like Sanity. For this, I usually create a container with styled-components, which allows me to write regular CSS while also using Tailwind classes via Twin.macro.

1const Input = styled.input`
2  color: purple;
3  ${tw`border rounded`}

Exploring the docs, I discovered twin.macro was providing the equivalent of !important when simply adding a trailing ! to any tailwind class.

1const Card = styled.div`
2  h2 {
3    ${tw`mt-0! mb-2! font-header!`}
4  }
5  a {
6    ${tw`hover:no-underline! text-gray-700! hover:text-gray-700!`}
7  }

Problem solved!

I'll admit this solution isn't as elegant as I'd wish but it does the job. I was able to enjoy the very nice and balanced styling provided by Tailwind Typography while keeping control over my code base.

Next step?

Let's work together!

If you'd like to talk about a project or need advice about product and ideation , simply drop me a message. I'm currently available for development projects, entrepreneurial gigs or speaking events.

You can also find me on:

  • github icon
  • linkedin icon
  • twitter icon

© 2023, Paul Gaumer