Skip Navigation

Scott Spence

Customising Fonts in Tailwind CSS and daisyUI

11 min read

Tailwind is awesome n’ all but what do you do when you want to change the default fonts. I’ve spent a bit of time customising this site to use local fonts above the default used in Tailwind CSS. In this post I’ll go over adding in new fonts for Tailwind and also extending the daisyUI themes.

If you not familiar, daisyUI is a plugin for Tailwind that adds a ton of additional utility classes component classes to enable you to move fast when building sites.

You can follow along in this post while I piece it all together or you can Tl;Dr and see the final code.

Local fonts

Ok, so I want to use fonts above the default that comes with Tailwind. In the past I’ve added the files for the fonts I wanted to use in a static or public folder and then used @font-face to load them into the global app.css file for Tailwind to use.

Then I found out about Fontsource (thanks to Matia) which is basically fonts that you install as dependencies.

Extend Tailwind theme

I’ll tackle adding fonts into Tailwind first. I’ll spin up a new SvelteKit project and install Tailwind and daisyUI using svelte-add.

The options I’m picking are Skeleton project, Yes, using TypeScript syntax and yes to all the additional options, if you’re following along, you do you.

The terminal commands are:

pnpm create svelte sveltekit-local-fonts
cd sveltekit-local-fonts
npx svelte-add@latest tailwindcss --daisyui --typography

I also did a post a while back on how to set up Svelte with Tailwind if you want to have a bit more detail on it.

I’ll also want to install the fonts I want to use from Fontsource so I’ll install them now too:

pnpm i -D @fontsource/poppins @fontsource/victor-mono

I want these fonts to be available to Tailwind so in the app.postcss file generated by svelte-add I’ve added in the fonts I want to use:

@import '@fontsource/victor-mono/400-italic.css';
@import '@fontsource/victor-mono/700-italic.css';
@import '@fontsource/victor-mono/400.css';
@import '@fontsource/victor-mono/700.css';
@import '@fontsource/poppins/400.css';
@import '@fontsource/poppins/500.css';
@import '@fontsource/poppins/600.css';
@import '@fontsource/poppins/700.css';
@import '@fontsource/poppins/800.css';
@import '@fontsource/poppins/900.css';

@tailwind base;
@tailwind components;
@tailwind utilities;

Just note that I’ve seen imports being used without the weights specified but when I have tried this way they are not rendered. Your experience may vary.

Now that the fonts are available to Tailwind I can use them in the tailwind.config.cjs file. Tailwind gives you three named font family options to use sans, serif and mono.

I just want to use Poppins for the sans option and Victor Mono for mono.

I’ll extend the theme object in the tailwind.config.cjs file and add in the fontFamily object defining the added fonts.

const config = {
  content: ['./src/**/*.{html,js,svelte,ts}'],

  theme: {
    extend: {
      fontFamily: {
        sans: ['Poppins', ...tailwind_theme.fontFamily.sans],
        mono: ['Victor Mono', ...tailwind_theme.fontFamily.mono],
        // or name them
        // 'victor-mono': ['Victor Mono'],
        // poppins: ['Poppins'],
      },
    },
  },

  plugins: [typography, daisyui],
}

In the example above I’m using the Tailwind default (named) names for the font families (sans, serif and mono), there’s also the option to name them yourself, I’ve commented out the lines to show you how.

If for some reason the local font is not available then I’ll want to fallback to the defaults offered by Tailwind. That’s why I’m spreading in the rest of the font families from Tailwind.

Here’s the full tailwind.config.cjs and you can see where I’m pulling out the defaultTheme from Tailwind as a variable and spreading the sans and mono font families into the theme.extend.fontFamily object for each font family.

const daisyui = require('daisyui')
const typography = require('@tailwindcss/typography')
const tailwind_theme = require('tailwindcss/defaultTheme')

/** @type {import('tailwindcss').Config}*/
const config = {
  content: ['./src/**/*.{html,js,svelte,ts}'],

  theme: {
    extend: {
      fontFamily: {
        sans: ['Poppins', ...tailwind_theme.fontFamily.sans],
        mono: ['Victor Mono', ...tailwind_theme.fontFamily.mono],
        // or name them
        // 'victor-mono': ['Victor Mono'],
        // poppins: ['Poppins'],
      },
    },
  },

  plugins: [typography, daisyui],
}

module.exports = config

So, now if I add some container classes to the src/routes/+layout.svelte file utilising the Tailwind prose plugin as well:

<script>
  import '../app.postcss'
</script>

<main class="container prose prose-xl mx-auto max-w-3xl px-4">
  <slot />
</main>

Then in the src/routes/+page.svelte file I can add in some text using the sans and mono font families:

<h1>Local Fonts with SvelteKit</h1>
<p>
  Using <a href="https://fontsource.org/"><code>@fontsource</code></a>
  to add local fonts.
</p>

<code>
  <pre>Also added mono-space font for code blocks.</pre>
</code>

I’m not naming the fonts I want to use because I set the fonts as the Tailwind named fonts so there’s no need to specify them as the Tailwind prose plugin will take care of the font selection, sizing and spacing for the markup.

Ok, so that’s basically it for adding in custom fonts to Tailwind.

If you want to use more than the Tailwind named fonts then you can define your own font names and use them in the markup like I detailed in the example. Just bear in mind that you’ll need to specify the font you want to use in the markup.

I’ll move onto doing something similar now with daisyUI.

When I say something similar I mean that I’ll be adding in different fonts for different themes in daisyUI.

Using daisyUI themes

I touched on daisyUI at the start, what I didn’t mention is that it comes with 29 themes out of the box 🤯.

To use all the daisyUI themes I’ll need to configure them in the tailwind.config.cjs file.

const daisyui = require('daisyui')
const typography = require('@tailwindcss/typography')
const tailwind_theme = require('tailwindcss/defaultTheme')

/** @type {import('tailwindcss').Config}*/
const config = {
  content: ['./src/**/*.{html,js,svelte,ts}'],

  theme: {
    extend: {
      fontFamily: {
        sans: ['Poppins', ...tailwind_theme.fontFamily.sans],
        mono: ['Victor Mono', ...tailwind_theme.fontFamily.mono],
        // or name them
        // 'victor-mono': ['Victor Mono'],
        // poppins: ['Poppins'],
      },
    },
  },

  daisyui: {
    themes: true,
  },

  plugins: [typography, daisyui],
}

module.exports = config

The daisyui.themes=true config means that I’m using all 29 daisyUI themes.

If I want to restrict this to just a few themes then I can use an array of theme names instead:

daisyui: {
  themes: ['dark', 'forest', 'wireframe'],
},

I’ll be using the previous configuration so I can cycle though all the themes.

All the daisyUI themes except Cyberpunk and Wireframe have the same font right now.

Once I’ve added in the daisyUI config I can change the daisyUI theme on the root app.html file in the project with the data-theme attribute on the html element.

So in this example I’m using the wireframe theme:

<!doctype html>
<html lang="en" data-theme="wireframe">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%sveltekit.assets%/favicon.png" />
    <meta name="viewport" content="width=device-width" />
    %sveltekit.head%
  </head>
  <body data-sveltekit-preload-data="hover">
    <div style="display: contents">%sveltekit.body%</div>
  </body>
</html>

Selecting a daisyUI theme

I recently did a post on Cookie-Based Theme Selection in SvelteKit with daisyUI and I’ll be using that now to cycle through the themes. If you need more detail on that then check out the post.

I’m going to rip the code from the sveltekit-theme-switch-example repo and add it to the example I’m building out here.

I’ll scaffold out the files I need to make the select component and the hooks file:

# -p created the parent directory if it doesn't exist
mkdir src/lib/themes -p
touch src/lib/themes/index.ts
touch src/lib/theme-select.svelte
touch src/hooks.server.ts

In the src/lib/themes/index.ts file I’ll copy the themes already in the example repo you can expand out the details button for the list if you like.

In src/lib/theme-select.svelte I’ll copy the code from the sveltekit-theme-switch-example repo.

Then add in the code for the src/hooks.server.ts file.

The to use the theme-select component I’ll add it to the src/routes/+layout.svelte file so it’s available to all child pages in the project (which is none but a good practice).

<script>
  import ThemeSelect from '$lib/theme-select.svelte'
  import '../app.postcss'
</script>

<ThemeSelect />
<main class="container prose prose-xl mx-auto max-w-3xl px-4">
  <slot />
</main>

Extend the daisyUI themes

Aight! Cycling though the themes now I can see that my custom font is being used in all the themes except cypherpunk and wireframe.

Why? Well, if I take a look at the daisyUI themes config for cyberpunk I can see that the fontFamily is set to a monospace font.

Here’s a snippet from the config file:

"[data-theme=cyberpunk]": {
  "color-scheme": "light",
  "fontFamily":
    "ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace",
  "primary": "#ff7598",
  "secondary": "#75d1f0",
  "accent": "#c07eec",
  "neutral": "#423f00",
  "neutral-content": "#ffee00",
  "base-100": "#ffee00",
  "--rounded-box": "0",
  "--rounded-btn": "0",
  "--rounded-badge": "0",
  "--tab-radius": "0",
},

I can override this in the tailwind.config.js file by amending the daisyui config. For illustration purposes I’ll change the cyberpunk font to use Comic Sans MS.

const daisyui = require('daisyui')
const typography = require('@tailwindcss/typography')
const tailwind_theme = require('tailwindcss/defaultTheme')

/** @type {import('tailwindcss').Config}*/
const config = {
  content: ['./src/**/*.{html,js,svelte,ts}'],

  theme: {
    extend: {
      fontFamily: {
        sans: ['Poppins', ...tailwind_theme.fontFamily.sans],
        mono: ['Victor Mono', ...tailwind_theme.fontFamily.mono],
        // or name them
        // 'victor-mono': ['Victor Mono'],
        // poppins: ['Poppins'],
      },
    },
  },

  daisyui: {
    themes: [
      {
        cyberpunk: {
          ...require('daisyui/src/theming/themes')[
            '[data-theme=cyberpunk]'
          ],
          fontFamily: 'Comic Sans MS',
        },
      },
    ],
  },

  plugins: [typography, daisyui],
}

module.exports = config

I found a GitHub discussion answered by Pouya (daisyUI creator) that details how to do this.

So changing that config now makes every theme the same as the cyberpunk theme, because that’s all that’s configured now. Makes sense, right?

Wait, what? Yeah! I’ll have to add a config for each theme I want to use. In this example that’s all 29 of them! 😱

Let’s take a look at that theme config again:

{
  cyberpunk: {
    ...require('daisyui/src/theming/themes')[
      '[data-theme=cyberpunk]'
    ],
    fontFamily: 'Comic Sans MS',
  },
},

Repeat that 29 times! That’s going to be a lot of code duplication!

Parametrised config

What I can do is create a function that takes the theme name as a parameter and returns the config object so I can be used in daisyUI. Then I can use that function to create the config object for each theme.

As I’m only looking to change the fontFamily I’ll add that as a parameter too. This can be further extended to allow for more customisation of the themes.

So, the function will look something like this:

function create_theme(theme_name, font_family) {
  return {
    [theme_name]: {
      ...require('daisyui/src/theming/themes')[
        `[data-theme=${theme_name}]`
      ],
      ...(font_family ? { fontFamily: font_family } : {}),
    },
  }
}

Then pass all the themes through that function to create the config object, if there’s no theme then it’s going to fallback to the daisyUI default same if there’s no font specified.

const daisyui_themes = [
  create_theme('acid'),
  create_theme('aqua'),
  create_theme('autumn'),
  // rest of the themes
]

See the full array here:

Then I can use that array in the daisyui config.

daisyui: {
  themes: daisy_themes,
},

Here’s the full tailwind.config.js file:

Now, if I select the cyberpunk theme, I get the Victor Mono font being used, I can now pass any specific font to any theme.

As I mentioned earlier, it’s not just the font that can be changed here, I can start modifying any of the daisyUI theme properties by extending the create_theme function.

Thanks

Thanks to Pouya for creating daisyUI I’ve been using it for a while now and it’s great! It’s pretty much the default I reach for now when starting a new project.

Massive thanks to Script Raccoon for helping me understand how to use a theme in the cookies! The dark mode toggle example they made, you can find that on their blog where they detail How to implement a cookie-based dark mode toggle in SvelteKit give it a read!

Conclusion

I’ve laid out and detailed how I’d go about this step-by-step. I hope you can get an idea on how to customize fonts in Tailwind with SvelteKit and daisyUI. I installed and integrated Fontsource fonts for local fonts to use in the project. I also demonstrated how to extend the Tailwind theme to incorporate theme.

I then looked as extending the daisyUI themes and how to modify them to use my preferred fonts. By creating a parameterized function, I avoided code duplication and provided a degree of customisation for each theme.

I hope you found this useful, if you did, please don’t forget to share it. 🙌

There's a reactions leaderboard you can check out too.

Copyright © 2017 - 2024 - All rights reserved Scott Spence