Default Components Styling
Learn how to style AudioUI's default components using the built-in theming system, CSS variables, and theme management utilities.
AudioUI's default components (Knob, Slider, Button, CycleButton, Keys) use a CSS variable-based theming system optimized for realtime audio applications. This system provides a clean, idiomatic way to customize component colors and styles without React Context or JavaScript overhead. For a high-level overview of theming on vector components, see Theming Features in the Vector introduction.
Note: This styling system applies to AudioUI's built-in default components. Fully customized components built with Control Primitives and custom view components use their own independent styling and theming systems.
Why a CSS Variable System?
Audio applications have strict performance requirements. The CSS variable approach ensures:
- Zero React overhead: Theme changes don't trigger re-renders
- Automatic updates: CSS handles theme changes instantly
- Dark mode support: Automatic adaptation via CSS
.darkclass - Animation support: Colors can be animated smoothly
- Framework agnostic: Works with any CSS-capable framework
How It Works
The color system uses a three-tier resolution hierarchy:
- Component prop (
colorprop on individual components) - Global CSS variable (
--audioui-primary-color) - Adaptive default (
--audioui-adaptive-default-color- white in dark mode, black in light mode)
When you set a color, AudioUI automatically computes variants (primary50, primary20) using CSS color-mix(). These variants are used for layered effects, borders, and visual depth.
Basic Usage
Setting Global Theme
Use the theme utility functions to set a global theme that applies to all components:
import { useEffect } from "react";
import { setThemeColor, setThemeRoundness } from "@cutoff/audio-ui-react";
import { Knob, Button } from "@cutoff/audio-ui-react";
export default function GlobalThemeExample() {
useEffect(() => {
// Set global theme (affects all components)
setThemeColor("#3b82f6"); // Blue
setThemeRoundness(0.3); // Slightly rounded
}, []);
return (
<div style={{ display: "flex", gap: "20px" }}>
<Knob value={0.5} onChange={(e) => {}} label="Cutoff" />
<Button value={false} onChange={(e) => {}} label="Power" />
</div>
);
}Using Predefined Colors
AudioUI provides predefined theme colors for convenience:
import { useEffect } from "react";
import { setThemeColor, themeColors } from "@cutoff/audio-ui-react";
import { Knob } from "@cutoff/audio-ui-react";
export default function PredefinedColorsExample() {
useEffect(() => {
// Use predefined colors
setThemeColor(themeColors.blue);
// Or: setThemeColor(themeColors.purple);
// Or: setThemeColor(themeColors.orange);
}, []);
return <Knob value={0.5} onChange={(e) => {}} label="Volume" />;
}Available predefined colors: default, blue, orange, pink, green, purple, yellow.
Per-Component Colors
Override the global theme for individual components:
import { Knob, Slider } from "@cutoff/audio-ui-react";
export default function PerComponentColorsExample() {
return (
<div style={{ display: "flex", gap: "20px" }}>
<Knob
value={0.5}
onChange={(e) => {}}
label="Cutoff"
color="#3b82f6" // Blue
/>
<Knob
value={0.5}
onChange={(e) => {}}
label="Resonance"
color="#ef4444" // Red
/>
<Slider
value={0.7}
onChange={(e) => {}}
label="Volume"
color="hsl(160, 95%, 44%)" // Green
/>
</div>
);
}Color Formats
The color prop accepts any valid CSS color value:
import { Knob } from "@cutoff/audio-ui-react";
export default function ColorFormatsExample() {
return (
<div style={{ display: "flex", gap: "20px", flexWrap: "wrap" }}>
<Knob value={0.5} onChange={(e) => {}} label="Named" color="blue" />
<Knob value={0.5} onChange={(e) => {}} label="Hex" color="#FF5500" />
<Knob
value={0.5}
onChange={(e) => {}}
label="RGB"
color="rgb(255, 85, 0)"
/>
<Knob
value={0.5}
onChange={(e) => {}}
label="HSL"
color="hsl(20, 100%, 50%)"
/>
<Knob
value={0.5}
onChange={(e) => {}}
label="CSS Variable"
color="var(--my-custom-color)"
/>
</div>
);
}Color Variants
AudioUI automatically generates color variants from your primary color:
primary50: 50% opacity variant (for backgrounds, tracks)primary20: 20% opacity variant (for subtle effects)
These variants are computed using CSS color-mix(), so they update automatically when the primary color changes. Components use these variants for layered visual effects:
import { Knob, Slider } from "@cutoff/audio-ui-react";
export default function ColorVariantsExample() {
return (
<div style={{ display: "flex", gap: "20px" }}>
{/* Knob uses primary50 for background arc, primary for foreground */}
<Knob value={0.5} onChange={(e) => {}} label="Knob" color="#3b82f6" />
{/* Slider uses primary50 for track, primary for fill */}
<Slider
value={0.7}
onChange={(e) => {}}
label="Slider"
color="#3b82f6"
orientation="vertical"
/>
</div>
);
}Adaptive Default Colors
When no color is specified, components use an adaptive default that automatically switches between light and dark modes:
- Light mode: Near-black (
hsl(0, 0%, 10%)) - Dark mode: Near-white (
hsl(0, 0%, 96%))
This ensures components are always visible regardless of your application's theme:
import { Knob } from "@cutoff/audio-ui-react";
export default function AdaptiveDefaultExample() {
// No color prop - uses adaptive default
return <Knob value={0.5} onChange={(e) => {}} label="Adaptive" />;
}CSS-Only Customization
You can customize themes using pure CSS without JavaScript:
export default function CSSOnlyThemeExample() {
return (
<>
<style>{`
.my-theme {
--audioui-primary-color: hsl(280, 80%, 60%);
--audioui-roundness-base: 0.5;
}
`}</style>
<div className="my-theme">
<Knob value={0.5} onChange={(e) => {}} label="Custom Theme" />
</div>
</>
);
}Or using inline styles:
import { Knob } from "@cutoff/audio-ui-react";
export default function InlineCSSThemeExample() {
return (
<div
style={{
"--audioui-primary-color": "hsl(200, 100%, 50%)",
"--audioui-roundness-base": "0.4",
} as React.CSSProperties}
>
<Knob value={0.5} onChange={(e) => {}} label="Inline Theme" />
</div>
);
}Roundness
Control the roundness of component corners using the roundness prop or global theme:
import { Knob, Button } from "@cutoff/audio-ui-react";
export default function RoundnessExample() {
return (
<div style={{ display: "flex", gap: "20px" }}>
<Knob
value={0.5}
onChange={(e) => {}}
label="Square"
roundness={0.0}
/>
<Knob
value={0.5}
onChange={(e) => {}}
label="Rounded"
roundness={0.5}
/>
<Knob
value={0.5}
onChange={(e) => {}}
label="Fully Rounded"
roundness={1.0}
/>
</div>
);
}Set global roundness:
import { useEffect } from "react";
import { setThemeRoundness } from "@cutoff/audio-ui-react";
export default function GlobalRoundnessExample() {
useEffect(() => {
setThemeRoundness(0.3); // Applies to all components
}, []);
return <Knob value={0.5} onChange={(e) => {}} label="Themed" />;
}Dynamic Theme Switching
Themes can be changed dynamically at runtime:
import { useState } from "react";
import { setThemeColor, themeColors } from "@cutoff/audio-ui-react";
import { Knob } from "@cutoff/audio-ui-react";
export default function DynamicThemeExample() {
const [currentTheme, setCurrentTheme] = useState(themeColors.blue);
const themes = [
{ name: "Blue", color: themeColors.blue },
{ name: "Purple", color: themeColors.purple },
{ name: "Orange", color: themeColors.orange },
{ name: "Green", color: themeColors.green },
];
const handleThemeChange = (color: string) => {
setThemeColor(color);
setCurrentTheme(color);
};
return (
<div>
<div style={{ display: "flex", gap: "10px", marginBottom: "20px" }}>
{themes.map((theme) => (
<button
key={theme.name}
onClick={() => handleThemeChange(theme.color)}
style={{
padding: "8px 16px",
backgroundColor:
currentTheme === theme.color ? theme.color : "#e5e7eb",
color: currentTheme === theme.color ? "white" : "black",
border: "none",
borderRadius: "4px",
cursor: "pointer",
}}
>
{theme.name}
</button>
))}
</div>
<Knob value={0.5} onChange={(e) => {}} label="Themed Knob" />
</div>
);
}Color Resolution in Practice
Understanding the resolution hierarchy helps when debugging theme issues:
- Component prop takes precedence: If you pass
color="red"to a Knob, it uses red regardless of global theme - Global theme is fallback: If no
colorprop, components use--audioui-primary-color - Adaptive default is final fallback: If no global theme is set, components use the adaptive default
import { useEffect } from "react";
import { setThemeColor, themeColors } from "@cutoff/audio-ui-react";
import { Knob } from "@cutoff/audio-ui-react";
export default function ResolutionExample() {
useEffect(() => {
setThemeColor(themeColors.blue); // Global theme
}, []);
return (
<div style={{ display: "flex", gap: "20px" }}>
{/* Uses global blue theme */}
<Knob value={0.5} onChange={(e) => {}} label="Global Theme" />
{/* Overrides with red */}
<Knob
value={0.5}
onChange={(e) => {}}
label="Override"
color="red"
/>
</div>
);
}Scope: Default Components Only
This styling system applies exclusively to AudioUI's default components:
- Knob - All variants (abstract, simplest, plainCap, iconCap)
- Slider - All variants (abstract, trackless, trackfull, stripless)
- Button - All variants
- CycleButton - All variants
- Keys - All key styles
Custom components built with Control Primitives and custom view components do not use this styling system. They implement their own styling and theming independently.
Best Practices
- Set global theme once: Use
setThemeColor()in your app's root component or layout - Use predefined colors:
themeColorsprovides consistent, tested color values - Override sparingly: Use per-component colors only when needed for specific UI elements
- CSS variables for scoped themes: Use CSS variables when you need theme scoping (e.g., different themes for different sections)
- Test in both modes: Always verify your colors work in both light and dark modes
Next Steps
- Learn about Default Components Sizing for component sizing
- Explore AdaptiveBox for layout and responsive behavior
- Explore Audio Parameters for parameter-based theming
- Check out Control Primitives for building custom components with independent styling
- See component-specific documentation for advanced styling options