Tailwind CSS
Class name utility and Tailwind v4 CSS support for styling Stream Deck components.
The cn utility is a lightweight class string concatenation function, similar to clsx or classnames. It filters out falsy values and joins the rest with spaces.
Import
import { cn } from "@fcannizzaro/streamdeck-react";tw is available as a backward-compatible alias:
import { tw } from "@fcannizzaro/streamdeck-react";tw is deprecated and will be removed in a future major version. Prefer cn for new code.
Signature
function cn(...args: Array<string | false | null | undefined | 0>): string;Usage
function MyKey() {
const [pressed, setPressed] = useState(false);
useKeyDown(() => setPressed(true));
useKeyUp(() => setPressed(false));
return (
<div
className={cn(
"flex items-center justify-center w-full h-full",
pressed && "bg-green-500",
!pressed && "bg-gray-800",
)}
>
<span className="text-white text-lg">{pressed ? "ON" : "OFF"}</span>
</div>
);
}How Tailwind Works in @fcannizzaro/streamdeck-react
The className prop is remapped to Takumi's tw prop during rendering. That means standard Tailwind utility classes work in your components without a CSS build step.
The cn() function itself only concatenates strings -- it does not resolve classes to styles. That resolution happens inside the renderer.
Tailwind vs Inline Styles
Prefer Tailwind classes for all static styling — layout, colors, spacing, typography, borders. This keeps your components concise and consistent.
Use inline style only for truly dynamic values that are computed at runtime (e.g., animation outputs, size.scale() values, or data-driven colors):
// ✅ Good: static layout and colors via Tailwind, dynamic value via style
<div className="flex items-center justify-center w-full h-full bg-[#1a1a2e]">
<span className="text-white font-bold" style={{ fontSize: size.scale(24) }}>
{value}
</span>
</div>
// ❌ Avoid: inline styles for static layout
<div style={{ display: "flex", alignItems: "center", justifyContent: "center",
width: "100%", height: "100%", backgroundColor: "#1a1a2e" }}>
<span style={{ color: "white", fontWeight: 700, fontSize: 24 }}>
{value}
</span>
</div>Prefer flexbox layout over absolute positioning. Tailwind's flex utilities (flex, flex-col, items-center, justify-center, gap-*) map directly to Takumi's layout engine.
Using with Themes
When using the CSS Theme System, you can reference theme variables in Tailwind arbitrary values:
<div className={cn("w-full h-full", "bg-[var(--color-surface)]")}>
<span className="text-[var(--color-primary)]">Themed</span>
</div>Tailwind v4 CSS Support
For full Tailwind v4 support — including @theme blocks, custom utilities, and standard CSS — use the stylesheets option in createPlugin(). This passes compiled CSS stylesheets directly to the Takumi renderer.
Setup
- Install
@tailwindcss/vite:
bun add -d @tailwindcss/vite- Add
tailwindcss()to your Vite plugins:
// vite.config.ts
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [
// ...other plugins
tailwindcss(),
streamDeckReact({
/* ... */
}),
],
// ...
});- Create a CSS file with your Tailwind v4 theme:
/* theme.css */
@import "tailwindcss";
@theme {
--color-primary: #4caf50;
--color-surface: #1a1a2e;
--color-text: #ffffff;
--color-text-muted: #888888;
}- Import it with
?inlineand pass it tocreatePlugin():
// src/plugin.ts
import { createPlugin, googleFont } from "@fcannizzaro/streamdeck-react";
import stylesheet from "./theme.css?inline";
const plugin = createPlugin({
stylesheets: [stylesheet],
fonts: [await googleFont("Inter")],
actions: [
/* ... */
],
});
await plugin.connect();Using in Components
With stylesheets configured, Tailwind v4 @theme tokens are available as first-class utility classes:
function ThemedKey() {
return (
<div className="flex items-center justify-center w-full h-full bg-primary">
<span className="text-text text-[18px] font-bold">Hello</span>
</div>
);
}This is more ergonomic than the var() syntax needed without stylesheets:
// Without stylesheets (using defineTheme + var()):
<div className="bg-[var(--color-primary)]">
// With stylesheets (using @theme):
<div className="bg-primary">stylesheets vs defineTheme
| Feature | defineTheme() + theme | stylesheets |
|---|---|---|
| Setup | No build tooling needed | Requires @tailwindcss/vite |
| Usage in components | bg-[var(--color-primary)] | bg-primary |
| Custom utilities | Not supported | Full @utility support |
| Standard CSS | Not supported | Full CSS support |
| Runtime switching | Via useTheme() | Static (build-time) |
Both approaches can be used together. defineTheme() tokens are available via var() references and support runtime switching with useTheme(), while stylesheets provides first-class Tailwind v4 integration for build-time themes.