@fcannizzaro/streamdeck-react

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

  1. Install @tailwindcss/vite:
bun add -d @tailwindcss/vite
  1. Add tailwindcss() to your Vite plugins:
// vite.config.ts
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [
    // ...other plugins
    tailwindcss(),
    streamDeckReact({
      /* ... */
    }),
  ],
  // ...
});
  1. 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;
}
  1. Import it with ?inline and pass it to createPlugin():
// 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

FeaturedefineTheme() + themestylesheets
SetupNo build tooling neededRequires @tailwindcss/vite
Usage in componentsbg-[var(--color-primary)]bg-primary
Custom utilitiesNot supportedFull @utility support
Standard CSSNot supportedFull CSS support
Runtime switchingVia 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.

On this page