Style leak from Svelte component - tailwind-css

Question:
I'd like to use a plugin (daisyUI) for TailwindCSS in one of my Svelte components. It looks like style information leaks from this component and affects the entire site. How can I avoid this?
I don't think this is related to daisyUI specifically.
Below I'm describing a minimal reproducible example based on sveltekit. But the problem is not related to sveltekit. I'm encountering this in the development of a webextension which doesn't use sveltekit. The sveltekit setup is only to make the smallest possible demonstration for this question.
To illustrate the problem, I've set up a sveltekit skeleton project, then added one single additional svelte component which uses Tailwind. When I add the plugin, the background color of my page turns from white to gray. I don't understand how this can happen, as far as I can see, I'm only using Tailwind within that component. But the style seems to leak.
Minimal example on github:
Fastest way to reproduce:
git clone git#github.com:lhk/minimum_example.git
cd minimum_example
npm install
npm run dev -- -- open
Now you can edit tailwind.config.cjs and add/remove the plugin:
plugins: [
//require("daisyui")
],
Step-by-step explanation
I'd like to use Svelte together with Tailwind and DaisyUI.
Here's a minimal project setup
# choose the skeleton project, typescript syntax and no to everything else
npm create svelte#latest minimum_example
cd minimum_example
npm install
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init tailwind.config.cjs -p
npm i --save-dev daisyui
Now edit tailwind.config.cjs:
/** #type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{html,js,svelte,ts}'], theme: {
extend: {},
},
plugins: [
//require("daisyui")
],
}
Add a new Svelte component under src/components/Problem.svelte:
<p class="bg-blue-700">Using Tailwind class</p>
<style lang="postcss">
#tailwind base;
#tailwind components;
#tailwind utilities;
</style>
And include it in src/routes/+page.svelte:
<script lang="ts">
import Problem from "./../components/Problem.svelte";
</script>
<h1>Welcome to SvelteKit</h1>
<p>Visit kit.svelte.dev to read the documentation</p>
<Problem></Problem>
You can run the project with
npm run dev -- -- open
If you open the website you'll see the sveltekit skeleton app, plus one paragraph with a blue background (this is my test that Tailwind is working). Now you can uncomment the plugin in tailwind.config.cjs. The background of the page will turn gray.
I think this is a theme that somehow leaks from the Tailwind plugin to the entire site.

The way you use tailwind with svelte is quite wrong. The tldr answer is remove #tailwind directives and use #apply instead.
<p class="my-element">Using Tailwind class</p>
<style lang="postcss">
.my-element {
#apply bg-blue-700;
}
</style>
The way how svelte scopes styles is by using a unique class name alongside your custom selector, e.g. .my-element becomes .my-element.svelte-x57u2q. This also means you must use a selector so that this scoping mechanism can kick in.
But with vanilla tailwind, those builtin class names have to be global in order to be useful, in other word “leaked”. This is by design, not bug.
So if you want to use tailwind but also leverage svelte’s scoped style, #apply is the only solution.
The official doc has a section titled Using #apply with per-component CSS that reveals more technical details, I think it’s worth reading.

Related

dark mode in tailwindcss with adonisjs project not working

I'm using TailwindCSS 2, vue 3, in an adonisjs project.
I have a simple html button, which when clicked should toggle to dark mode on/off.
If I use the tailwindcss cdn version, and set darkmode in the config in the html, everything works fine. If I use my css, it doesn't. I guess I'm missing some step.
My tailwind.config.js does have the darkMode: 'class' definition
content: ["./resources/**/*.{edge,js,ts,jsx,tsx,vue}"],
darkMode : 'class',
options: {
safelist: ['dark']
},
I prepare the css using the command:
npx tailwindcss -i resources/css/style.css -o resources/css/app.css
I load the asset using adonisjs assets
<link href="{{asset('assets/css/app.css')}}" rel="stylesheet">
when I click in the button, I can see that the html tag now has the "dark" class, but nothing happens. The background does not change. The body tag has "dark:bg-slate-800" definition.
But like I said, if I use the cdn version, everything works.
Am I missing a configuration step?
I fixed my issue doing a few things:
reinstalled the packages described here https://tailwindcss.com/docs/guides/adonisjs (maybe I had missed something)
moved my css to app.css
added an style entry point in webpack.congfig.js:
Encore.addStyleEntry('style', './resources/css/app.css')
now I load my css using:
#entryPointStyles('style')
now when I run "npm run dev" I guess tailwind is run under the hood by webpack and everything is working

Next JS - How to apply Tailwind to specific pages

I want to migrate an existing Next JS project to Tailwind CSS.
Is there a way to ensure Tailwind and Preflight/any default style only applies to specific pages? I basically need some pages to remain 100% untouched by Tailwind.
Things I've tried
Modifying the content option in tailwind.config (that only affects the classes) and doesn't stop Tailwind applying base styling
Applying global.css which has the Tailwind css conditionally (haven't been able to figure out how to do this)
Disabling preflight. You can only do this for all pages or none of them
I also have the same issue; so far I've found one solution that is more like a workaround than a solution.
First step
Install the postcss-nested plugin for postcss and then create a CSS class to scope tailwind:
.tailwind-layout {
#tailwind base;
#tailwind components;
#tailwind utilities;
}
Second step
Create a react hook to use on the target pages:
import { useEffect } from 'react';
export default function useTailwindLayout() {
useEffect(() => {
const body = document.querySelector('body');
body?.classList.add('tailwind-layout');
return () => {
body?.classList.remove('tailwind-layout');
}
}, []);
}
Third step
Use the hook on target pages components:
useTailwindLayout();
Issue
Tailwind show the following warning on console:
(2:5) Nested #tailwind rules were detected, but are not supported.
Consider using a prefix to scope Tailwind's classes:
https://tailwindcss.com/docs/configuration#prefix
But so far, everything is working fine. I didn't find any issues or unexpected behavior. If I find a better solution, I'll update this answer.

"Term Expected" error in tailwindcss generated css

I am working on an node.js express project using EJS as template engine. I am developing this on Intellij Ultimate Edition. Intellij's tailwind css plugin is installed. I am using tailwindcss v3 as my css framework. I have followed their Get Started guide and I am using Tailwind CLI as my method of installation.
tailwind.config.js
module.exports = {
mode: 'jit',
content: ['./views/*.ejs'],
theme: {
extend: {},
},
plugins: [],
};
I am building the css like so:
npx tailwindcss -i source.css -o public/stylesheets/style.css --watch
source.css
#tailwind base;
#tailwind components;
#tailwind utilities;
So all is working fine, no issues, however I am a no error/warning in IDE kinda fellow (read OCD), and the error/warning shown in the IDE is bothering me and I want to know how to fix it OR if it is meant to be this way, then how to suppress it?
I have added a screenshot for reference. Let me know if more info is needed to debug, I'll be happy to provide them.
(Answering my own question)
So, looks like #tailwind base; is the culprit.
According to tailwind doc:
Built on top of modern-normalize, Preflight is a set of base styles for Tailwind projects that are designed to smooth over cross-browser inconsistencies and make it easier for you to work within the constraints of your design system.
Tailwind automatically injects these styles when you include #tailwind base in your CSS
Looks like this has some styles which Intellij thinks are wrong and hence shows errors/warnings. You can read more about it here.
Quick solution is to remove #tailwind base; from your source/input.css, and it seems safe to remove as long as you are fine having minor inconsistencies between browsers.
I will reconsider my decision of removing it as my app matures. Not sure if it is an IntelliJ issue or a Tailwind issue. Please advice and I can open up an issue accordingly.
EDIT:
I found a way to disable IntelliJ inspection to just one file. This solution is imo a better one than removing #tailwind base from your source.css
You can do this by opening the culprit file and going over to the inspection bubble (top right, with checkmarks, crosses etc) and then click on Highlight:None.
I have also started a discussion on the tailwindcss git repo here.

How to make tailwindcss and scss work together?

I'm trying to make tailwindcss and scss work together, but I have some issues. I've tried 2 options
1 - rails new app_name -c tailwind - works fine, but I cannot use nested selectors, such as
p {
h1.name {
#apply text-9xl;
}
}
2 - rails new app_name -c postcss - works almost fine, I can use nested selectors with my postcss config
module.exports = {
plugins: [
require('tailwindcss'),
require('tailwindcss/nesting'),
require('autoprefixer')
]
}
but I cannot use #import statement wit taiwindcss code (basic CSS code works fine).
application.scss
#tailwind base;
#tailwind components;
#tailwind utilities;
#import "external";
external.scss
h1 {
#apply text-9xl;
}
body {
background: red;
}
In this example body is read, but text-9xl isn't applied to h1. How to fix it?
PS: I use ruby on rails 7.0.1 with cssbundling-rails gem
It was discussed a week ago in this issue.
For now if both Tailwind and PostCSS are required,
then you'll need the whole Node enchilada
as DHH stated in the discussion. Or, you can use this hack that is based on extra pre-compilation step of joining all css files into one.
Or, you can wait until this step gets into tailwindcss-rails gem.
It also worth noting that #apply is not recommend for general purposes in tailwind. As stated in the docs:
Whatever you do, don’t use #apply just to make things look “cleaner”. Yes, HTML templates littered with Tailwind classes are kind of ugly. Making changes in a project that has tons of custom CSS is worse.
If you start using #apply for everything, you are basically just
writing CSS again and throwing away all of the workflow and
maintainability advantages Tailwind gives you, for example:
Maybe, there is no actual need for all these tricks just for the sake of #apply.

How to use SASS to rewrite custom CSS methods from an external Vue module?

I'm using a third-party module in our Vue project called vue-cal, which is for rendering a calendar. You can customise how your date cells look and such, using their custom css like this.
<style>
.vuecal--month-view .vuecal__cell-content {justify-content: flex-start;}
.vuecal__cell.selected {background-color: red;}
</style>
However, we use sass for our project, and I tried rewriting it like below but now the <style> isn't being applied at all. How can I rewrite this in sass correctly, or is there no way to rewrite external libraries' custom methods like these in non-css syntax?
<style lang="sass" scoped>
.vuecal--month-view
.vuecal__cell-content
justify-content: flex-start
.vuecal__cell.selected
background-color: red
</style>
Sorry if this is a basic question - still a beginner to Vue, CSS and front-end in general.
[EDIT] Forgot to mention an important detail. We already use sass-loader#7.1.0, and I've already written some other code in sass for other components. Those are being rendered fine. That's why I'm wondering if it has to do with vue-cal-specific methods.
You need to use vue-loader to pre-process the SASS into native CSS
Step 1:
npm install -D sass-loader sass
Step 2, in your webpack config file, make sure to have:
module.exports = {
module: {
rules: [
// ... other rules omitted
// this will apply to both plain `.scss` files
// AND `<style lang="scss">` blocks in `.vue` files
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
]
}
]
},
// plugin omitted
}
This is the barebones needed. For further information see:
vue-loader documentation
[SOLVED]
It turned out that the problem was not sass, but the fact that the style was scoped. Scoped styles are only applied to the component itself, but vue-cal is an external module so the styles weren't applied. Removing scoped immediately fixed the issue.

Resources