tailwind
Adds a tailwind plugin to esbuild.build for css files.
I could not find how to pass a custom configuration directly, so I'm currently creating an intermediate root/.observablehq/cache/tailwind.config.js to direct tailwind to the project files, so it can analyze the "content" that might contain relevant class names.
And you can use it like so in your page.md:
<div class="tw-rounded-xl tw-p-8 tw-text-lg tw-font-mono tw-bg-black tw-text-white">
Hello, tailwind
</div>
This intermediate file imports {src}/tailwind.config.js if it exists, allowing the user to configure tailwind, for example by setting prefix: "".
Here's another example with a custom src/tailwind.config.js file:
/** @type {import('tailwindcss').Config} */
export default {
theme: {
colors: {
"almost-white": "#fefefe",
"bubble-gum": "#ff77e9",
}
},
plugins: []
};
You can then use the new colors:
<div class="tw-rounded-xl tw-p-8 tw-text-lg tw-font-mono tw-bg-bubble-gum tw-text-almost-white">
Hello, tailwind
</div>
The way tailwind works, is by scanning all the "content" files (in our case, the markdown, js, and page loaders), for strings that match its classnames, and then builds the corresponding styles.
TODO:
- [ ] revise in light of v4 https://tailwindcss.com/blog/tailwindcss-v4
- [x] figure out dark mode (using the "selector" strategy, I guess)
- [ ] adopt an automatic "dark/light" class that reflects the color-scheme property (#1780)
- [x] fix tests
- [x] figure out hashing
- [x] fix live preview
- [ ] make the tailwind config part of the framework config
- [ ] adopt tailwind’s grid? maybe slightly adapted?
- [ ] customize breakpoints
- [ ] use
@containerbreakpoints, adapt to the true available size (depending on toc)
- [ ] use
- [ ] fix everything that is reset
- [ ] h1…h6 (dirty patch for now)
- [ ] lists
- [ ] others?
- [ ] add tests
- [x] document
closes #595 supersedes #596
Here's a solution for dark mode:
Add darkMode: ["variant", "&:where([class~=dark], [class~=dark] *)"] to the default tailwind config, then add a javascript class toggle on the root.
```js
document.querySelector("html").classList.toggle("dark", dark);
```
<div class="
tw-bg-white dark:tw-bg-black
tw-text-red-600 dark:tw-text-emerald-600
">
TEST DARK MODE
</div>
it could be better (I think framework should add the darkclass on the root in parallel with the color-scheme property), but it works. The standard tailwind color classes work in dark mode out of the box, so that's good too.
We should also coordinate this with #1638
Another thing to figure out is the hash. I don't think we want to update the css each time any md or js file changes… so maybe we have to watch all these files for changes in the list of statically analyzable "potential tailwind class names" that they contain.
In preview we could generate a tailwind.css that is specific to just the current page (+ any imported local modules) rather than continuously trying to recompute it for the entire app.
I've updated the logic a bit, now we have continuous updating of a separate tailwind.css
(It's still not limited to the current page, because I don't know how to pass an object configuration—it seems it only wants a file-based configuration).
I've had to blocklist the grid classes, since they conflict with ours. I guess it's going to be a fork in the road: continue with our own grid, or switch to tailwind's. The difference is that in tailwind you have to be explicit about your breakpoints.
Speaking of breakpoints we should make sure we use the same. DONE
I've now tested tailwind plugins, it just works. For example,
yarn add --dev @tailwindcss/typography
then in docs/tailwind.config.js:
import typography from "@tailwindcss/typography";
export default {
plugins: [ typography ]
};
Do we need to change the default breakpoints for tailwind? Users may find that surprising.
These are the breakpoints of framework, my assumption here is that users are working inside “main” so the reference for sizes is the width of main.
Here's a way to test:
## breakpoints
<ul>
<li><span class="text-red-500"><sm</span> (always on)</li>
<li><span class="sm:text-red-500">sm</span></li>
<li><span class="md:text-red-500">md</span></li>
<li><span class="lg:text-red-500">lg</span></li>
<li><span class="xl:text-red-500">xl</span></li>
</ul>
if we leave tailwind's breakpoints unchanged, these element light up at very "random" places.
(It's the same issue that the tailwindcss-container-queries plugin addresses.)
These are the breakpoints of framework, my assumption here is that users are working inside “main” so the reference for sizes is the width of main.
That probably makes sense, then. If they want to reset it they can do that in their own config file, but this change is probably more good than unexpected :-)
The reference is here, with an example showing the contorsions you have to do when you have a sidebar. https://v1.tailwindcss.com/docs/breakpoints
In our case it's even more complicated, because the space available to draw stuff (which I believe is what should drive the definitions of sm, md, lg), depends on whether the TOC is shown, and on the themes used (e.g. wide). And that's not only a function of css and the page width… I have a hunch that the @container approach might not be fully correct either because the toc is an aside, so we have to substract its width from the value. But we're already using this container for our own grids, so maybe I'm missing something?
(I don't like the way the TOC works, and the fact that it is not visible at all on smaller screens is also problematic, so it might be the final draw telling that we have to rewrite it with tailwind.)