United Kingdom: +44 (0)208 088 8978

Transform your CSS into fable bindings with fable-css-modules

In this blog post Dragos has a look the 'fable-css-modules' library

We're hiring Software Developers

Click here to find out more

Introduction

Here at CIT we love F#! We love it so much that we petitioned for it to be an officially recognized spoken language at the UN. When they rejected us, we just had to let! bygones be bygones.

When developing websites we might need to make use of CSS classes, this is how we can we do in Feliz:

        Html.h5 [
            prop.className "container"
            prop.text "Hello World!"
        ]

Not very FSharpy is it?

We rely on a string to call a css class called container, wouldn't it be nicer if we could use bindings?

That's why I would like to show you to this nifty library called fable-css-modules, it can generate fable bindings for your Fable application so you can get the true F# experience.

This library is an npm tool that can be installed as an npm package:

npm install fable-css-modules

You still have to write the css class but at least you no longer have to reference it with a string; let me give you an example:

If we already have a css file (in the root folder of our project for example), we need to make sure that it has the ".module" extension added before the ".css" to our file, as that's how the library identifies it.

style.module.css

Create some classes:

.gap-5px {
    gap: 5px;
}

.container {
    background-color: red;
    width: 300px;
}

Use this command in your terminal in the directory where your css is:

npx fcm

Note: Be aware that it will convert css modules in nested folders as well, including those in your node_modules folder

With the creation of the 'CssModules.fs' module, we've officially crossed over into the whimsical world of F#! Now, your CSS classes have magically transformed into F# bindings, ready to be sprinkled throughout your application!

type style =

    /// <summary>
    /// Binding for <c>gap-5px</c> class
    /// </summary>
    [<Emit("$0[\"gap-5px\"]")>]
    abstract gap5px : string

    /// <summary>
    /// Binding for <c>container</c> class
    /// </summary>
    [<Emit("$0[\"container\"]")>]
    abstract container : string

Note: Don't forget to add CssModules.fs to your .fsproj

And now you can use in places like Feliz, as the documentation shows us, for this example I am using a Feliz template:

I added this in the Components.fs file:

module Styles = 
    open Fable.Core.JsInterop

    let private classes : CssModules.style = import "default" "./css-files/style.module.css"

    let sample =
        Html.h5 [
            prop.className classes.container
            prop.text "Hello World!"
        ]

Let's take a quick look at the code:

open Fable.Core.JsInterop imports Fable's JavaScript interoperability functions.

import "default" "./css-files/style.module.css" is where Fable's JavaScript interoperability comes into play. This line imports the default export from the CSS module located at ./css-files/style.module.css.

And now, call it somewhere like this:

Styles.sample

And you should see this:

Conclusion

In this blog post we had a look at how to make better use of F# in our web applications by creating bindings for our css classes thanks to the fable-css-modules library!