Is there a way for tailwind.config.js to auto bundle dynamic class attributes on leptos

622 views Asked by At

so I was trying out tailwindcss with leptos framework, what I noticed is when classes are included in static class attribute, the tailwindcss config recognize and build up those in output.css. however if I was to include class name using Dynamic Classes in leptos framework, those classes are not being auto included in output.css. Eg. 'rounded-lg' style won't be included in output.css

use leptos::*;
use leptos_meta::*;

#[component]
fn App(cx: Scope) -> impl IntoView {
    let (count, set_count) = create_signal(cx, 0);
    provide_meta_context(cx);

    view! { cx,
        <Stylesheet id="leptos" href="/pkg/tailwind.css"/>
        <button
            class="p-1 px-2.5 bg-sky-500 hover:bg-sky-700 focus:outline-none focus:ring focus:ring-sky-300 hover:text-white"
            class:rounded-lg=move || count() % 2 == 1
            on:click=move |_| {
                set_count.update(|n| *n += 1);
            }
        >
        "Click me: " {move || count()}
        </button>
    }
}

fn main() {
    leptos::mount_to_body(|cx| view!{ cx, <App/> })
}

I had to manually add those styles to output.css, wondering if there is better way to auto extract that rather than adding it manually all the time.

2

There are 2 answers

1
Joel Mueller On

Leptos also supports a tuple-based syntax for dynamic classes, and this works with the default Tailwind parser:

class=("rounded-lg", move || count() % 2 == 1)

That said, you can make the other syntax work as well. If you add a space after class:, Tailwind will find the dynamic class names, and Leptos will continue to compile successfully.

That is to say, turn this:

class:rounded-lg=move || count() % 2 == 1

Into this:

class: rounded-lg=move || count() % 2 == 1

Or this:

class: rounded-lg = move || count() % 2 == 1

It's also possible to customize the Tailwind parsing for Rust files. The following example tailwind.config.js configures Tailwind to successfully parse the tailwind classes from class="p-1 bg-sky-500" and class:rounded-lg=move || count() % 2 == 1 and class=("rounded-lg", move || count() % 2 == 1) in Rust files.

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: {
    files: ["*.html", "./src/**/*.rs"],
    extract: {
      // Support for leptos class:classname=predicate and 
      // class=("classname", predicate) syntax.
      // Without this the tuple syntax works but not 
      // the inline syntax.
      rs: (content) => content
        .match(/(?<=class[:=]\(?"?)[-\w: ]+/g)
        ?.flatMap(s => s.split(' ')) ?? []
    }
  },
  theme: {
    extend: {},
  },
  plugins: [],
}
2
treckstar On

You could try using the Safelisting classes tailwind.config.js option.

/** @type {import('tailwindcss').Config} */
module.exports = {
  safelist: [
    'rounded-lg'
  ],
  theme: {
    extend: {
      // ...
    },
  },
  plugins: [],
}
Check out this example I created here with that config setting. https://play.tailwindcss.com/Bpz8xH6Edk?file=config

Even though there is no HTML being output, the rounded-lg class still gets included into the compiled CSS.

Tailwind Play example of Safelisting classes.

There is another option which is shown under Working with third party libraries.

@tailwind base;
@tailwind components;

.c-rounded-lg {
  @apply rounded-lg;
}

/* ... */

@tailwind utilities;

This will ensure that Tailwind always includes those styles in your CSS, which is a lot easier than configuring Tailwind to scan the source code of a third-party library.

We recommend writing those styles without using Tailwind’s @layer feature