tailwind-style-sheets
v0.0.1
Published
A Turbopack loader and Next.js plugin for `.twss` files — co-locate your Tailwind class maps alongside components.
Downloads
99
Readme
tailwind-style-sheets
A Turbopack loader and Next.js plugin for .twss files — co-locate your Tailwind class maps alongside components.
What it does
.twss files use a CSS-like syntax to define named Tailwind class groups. Each class can be written on its own line — this is the preferred style as it keeps diffs clean and classes easy to scan:
/* Button.styles.twss */
.button {
@apply
cursor-pointer
px-4
py-2
rounded-full
text-sm
font-medium
transition-all
active:scale-95
}
.button--primary {
@apply
bg-blue-600
text-white
hover:bg-blue-700
}
.button--ghost {
@apply
bg-transparent
text-blue-600
hover:bg-blue-50
}Inline is also valid:
.button {
@apply cursor-pointer px-4 py-2 rounded-full text-sm font-medium transition-all active:scale-95
}Importing a .twss file gives you a plain object:
import styles from "./Button.styles.twss";
// styles.button → "cursor-pointer px-4 py-2 rounded-full text-sm font-medium transition-all active:scale-95"
// styles["button--primary"] → "bg-blue-600 text-white hover:bg-blue-700"
// styles["button--ghost"] → "bg-transparent text-blue-600 hover:bg-blue-50"Pair it with @michalshelenberg/modcn to compose BEM classes ergonomically:
import { modcn } from "@michalshelenberg/modcn";
import styles from "./Button.styles.twss";
const cn = modcn(styles);
export function Button({ variant = "primary", className, children, ...props }) {
return (
<button {...props} className={cn("button", `button--${variant}`, className)}>
{children}
</button>
);
}Installation
npx tailwind-style-sheets initThis scaffolds all required files and installs the package.
Manual installation
npm install tailwind-style-sheetsnext.config.ts
import type { NextConfig } from "next";
import path from "path";
import { withTwssPlugin } from "tailwind-style-sheets";
const nextConfig: NextConfig = {};
export default withTwssPlugin(nextConfig, {
globalsCSS: path.resolve(__dirname, "src/app/globals.css"),
watchDir: path.resolve(__dirname, "src"),
});withTwssPlugin options:
| Option | Type | Description |
| ------------ | -------- | ------------------------------------------------------------------------------------ |
| globalsCSS | string | Absolute path to your global CSS file. Touched on .twss changes to trigger HMR. |
| watchDir | string | Directory to watch recursively for .twss file changes. Only active in development. |
Both options are optional. Omitting them disables the HMR watcher (the loader still works).
TypeScript
Add a declaration file so TypeScript knows .twss imports return Record<string, string>:
// global.d.ts
declare module "*.twss" {
const styles: Record<string, string>;
export default styles;
}VSCode
Install the Tailwind CSS IntelliSense extension to get Tailwind class autocomplete and hover previews inside .twss files.
Add to .vscode/settings.json to get CSS syntax highlighting and silence the @apply warning:
{
"css.lint.unknownAtRules": "ignore",
"files.associations": {
"*.twss": "css"
}
}How it works
Loader (
loader.ts) — Turbopack passes the raw.twssfile content through the loader. A regex extracts each.className { @apply ... }block and converts it toexport default { className: "class1 class2 ..." }.HMR watcher (
plugin.ts) — In development,fs.watchmonitorswatchDirfor.twsschanges. When a change is detected, it touchesglobalsCSS, which causes Next.js to re-run Tailwind's class scan and hot-reload styles.
