United Kingdom: +44 (0)208 088 8978

Getting Feliz.DaisyUI and the Fable plugin for Vite to play nice

In this blog Joost discusses the challenges he encountered trying to get Feliz.DaisyUI working with the Fable plugin for vite

We're hiring Software Developers

Click here to find out more

I recently set out to write a blog post on the new features added in DaisyUI v5, and Feliz.DaisyUI v5. Of course, I can't write about something without having a good play around with it, so I started by setting up a new project, including the Fable plugin for Vite. I soon realized that the Fable plugin for Vite and Feliz.DaisyUI don't play together nicely out of the box. In this blog post, I will explain why, and how you can work around this issue.

TL;DR

Feliz.DaisyUI only works when using the Fable plugin for Vite when you add the following lines to your css file:

 @import 'tailwindcss';
+@source 'fable_modules/Feliz.DaisyUI.5.0.0/DaisyUI.fs';
+@source 'fable_modules/Feliz.DaisyUI.5.0.0/Modifiers.fs';

Daisy is not applied!

After setting up my application using Daisy 5 and the Fable plugin for Vite, I added a simple button to the page, expecting to see a nicely styled DaisyUI button.

let button =
    Daisy.button.button [
        button.outline
        button.primary
        button.lg
        prop.text "My button"
    ]

let root = ReactDOM.createRoot (document.getElementById "root")
root.render button

But on running the app, the button was rendered with no styling at all:

A plain string on a webpage

But I was able to add my own styling, for example by adding the class "font-bold" to the button:

A bold string on a webpage

Making it clear that the problem lies in the classes emitted by DaisyUI, and not in Tailwind.

After some playing around without being able to fix the issue, I decided to start stripping down any differences between this project and others where I use DaisyUI. One of those differences is the use of the Fable plugin for Vite. This plugin streamlines setting up Fable projects, by combining the step of transpiling F# into JavaScript, either for bundling or serving it up in the development server. One of the consequences of this is that the result of this compilation is not written to disk by Fable to immediately be read by React, potentially boosting performance. After switching back to the old school of serving using Fable and Vite separately, I was presented with a beautifully styled button:

An button with DaisyUI styling on a webpage

Tailwind and the file system

By now, it's clear the issue is that Feliz.DaisyUI and the Fable plugin for Vite don't play nicely. To understand this issue, it's important to understand how Tailwind works, as DaisyUI is built on Tailwind.

Tailwind provides CSS styling based on classes that you add to HTML elements. It's very flexible and allows you to construct your own classes by following specific patterns, for example by combining 'text' with a color description. If Tailwind provided all those classes by default, that would make for a very chunky CSS file. Instead, Tailwind scans your files to detect the classes you actually use, and generates those classes only. This makes it so that as a developer, you need to be mindful that your classes are verbatim in your source code.

By default, Tailwind searches only in non-gitignored files; this is not a problem when using Fable directly, as the classes used from Feliz.DaisyUI end up in our transpiled .fs.js files. When we're using the Vite plugin, these files don't exist on our filesystem, and Tailwind can't pick them up. Fortunately, there's a simple solution to this: Vite allows you to explicitly add files to detect classes in. By adding the file that contains the classes in Feliz.DaisyUI, our app is nicely styled once again!

In projects not using the Fable plugin for Vite, you'll probably .gitignore the .fs.js files generated by Fable, so you'll also need to use @source to allow these to be picked up by the Tailwind watcher

A button with DaisyUI styling on a webpage

@import 'tailwindcss';
@source 'fable_modules/Feliz.DaisyUI.5.0.0/DaisyUI.fs';
@source 'fable_modules/Feliz.DaisyUI.5.0.0/Modifiers.fs';
...
@plugin 'daisyui' {};

This example uses the CSS-based configuration introduced in Tailwind 4; for projects running on earlier versions of Tailwind, this setting can be set in tailwind.config.js

Note that this will make our bundle a bit larger, as it now contains all of the classes that DaisyUI uses, instead of just the ones we use in our app.

Conclusion

The Fable plugin for Vite is a really nice addition to the F# family, but sometimes using it may have unexpected side effects! It's a good reminder to always be wary of unwanted interplay between tools used in your stack. I created an issue on the Feliz.DaisyUI repository to further discuss this issue!