Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conditional tailwind classes are not automatically included #2890

Closed
maxbergmark opened this issue Aug 28, 2024 · 6 comments · Fixed by #3143
Closed

Conditional tailwind classes are not automatically included #2890

maxbergmark opened this issue Aug 28, 2024 · 6 comments · Fixed by #3143

Comments

@maxbergmark
Copy link

maxbergmark commented Aug 28, 2024

When using Tailwind CSS with the view! macro, there are some quirks related to conditional Tailwind classes. Within the macro, using the class:class-name=move || condition syntax won't trigger Tailwind to include the class. But adding the class name as a comment within any view macro will cause the class to be included, and will render the component as expected.

Non-working example

use leptos::*;

fn main() {
    mount_to_body(|| {
        view! { <p
            class:text-orange-600=true
        >"This text should be orange"</p> }
    })
}

Working example

use leptos::*;

fn main() {
    mount_to_body(|| {
        view! { <p
            // text-orange-600
            class:text-orange-600=true
        >"This text should be orange"</p> }
    })
}

Leptos Dependencies

leptos = { version = "0.6.14", features = ["csr", "nightly"] }

To Reproduce
Steps to reproduce the behavior:

  1. Create CSR application following the Getting Started guide
  2. Add Tailwind CSS using the Tailwind CSR example
  3. Paste the non-working example above into main.rs
  4. trunk serve --open
  5. See error

Expected behavior
I would expect the conditional Tailwind classes to get compiled too, without having to add them separately as a comment.

Screenshots

image image
@gbj
Copy link
Collaborator

gbj commented Aug 28, 2024

I'm not sure this is an actionable issue, from the framework's perspective: i.e., there's no commit to the codebase of Leptos that could solve this problem for you.

I think it's something that can either be fixed by adjusting the Tailwind config (setting up Tailwind to check for class: prefixes too? I am not familiar enough with Tailwind to know the answer here) or, alternately, by using the "complicated class" syntax (class=("text-orange-600", move || true)) which should detect it because now it's a separate string.

If it is possible to do it by adjusting Tailwind config then I guess a PR to update the example Tailwind config would be welcome!

@maxbergmark
Copy link
Author

Good suggestions! I'll try them out, and see what the outcome is.

@maxbergmark
Copy link
Author

@gbj As you suspected, this doesn't sound like it is a Leptos problem, but more of a Tailwind problem. Still, I would argue that it's a bit confusing that adding code comments fixes the problem. Using the "complicated class" syntax also does the trick, as does adding a space after class:".

Working example

use leptos::*;

fn main() {
    mount_to_body(|| {
        view! { <p
            class: text-orange-600=true
        >"This text will be orange"</p> }
    })
}

I made an attempt to solve the problem through the tailwind config. I'm no JS expert, but this seems to work for both regular class definitions, and those using the class: syntax:

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: {
        files: ["./*.html", "./src/**/*.rs"],
        extract: (content) => {
            const matches = content.match(/(class:)?(\w+[-\w]*\w+)/g) || [];
            return matches.map((match) => match.replace(/^class:/, ''));
        },
    },
    theme: {
        extend: {},
    },
    plugins: [],
};

Feel free to suggest changes to the above tailwind config, but I think it could be a good idea to update the documentation, and describe the problem briefly in the getting started guide for Tailwind CSR in Leptos.

@maxbergmark
Copy link
Author

I cleaned up the tailwind config a bit, and made sure that it works as expected.

Tailwind config

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: {
        files: ["./*.html", "./src/**/*.rs"],
        extract: (content) => {
            const matches = [...content.matchAll(/(class:)?(\w+[-\w]*\w+)/g)];
            return matches.map((match) => match[2]);
        },
    },
    theme: {
        extend: {},
    },
    plugins: [],
};

Example main.rs

use leptos::*;

fn main() {
    mount_to_body(|| {
        view! { <p
                class:text-orange-500=true
            >"This text should be orange"</p>
        <p class="text-blue-500">This text should be blue</p> }
    })
}

Screenshot

image

@agraboso
Copy link
Contributor

FYI: https://stackoverflow.com/questions/76133187/is-there-a-way-for-tailwind-config-js-to-auto-bundle-dynamic-class-attributes-on

@jheuel
Copy link
Contributor

jheuel commented Oct 22, 2024

Transforming the input is less work than changing the extractor:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: {
    files: ["*.html", "./src/**/*.rs"],
    transform: {
      rs: (content) => content.replace(/(?:^|\s)class:/g, ' '),
    },
  },
  theme: {
    extend: {},
  },
  plugins: [],
}

@gbj gbj closed this as completed in #3143 Oct 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants