or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions.mdcli-commands.mdframework-support.mdhighlighting.mdindex.mdmanager-api.mdstory-composition.mdtesting.mdtheming.mdviewport.md

theming.mddocs/

0

# Theming and Customization

1

2

Complete theming system for customizing Storybook's UI appearance with pre-built themes and custom theme creation capabilities. Built on top of Emotion CSS-in-JS library for dynamic styling and theme switching.

3

4

## Capabilities

5

6

### Theme Creation

7

8

Create custom themes for Storybook's manager UI with extensive customization options.

9

10

```typescript { .api }

11

/**

12

* Create a custom theme with optional variable overrides

13

* @param vars - Partial theme variables to override defaults

14

* @param rest - Additional theme properties

15

* @returns Complete theme object with all variables resolved

16

*/

17

function create(vars?: ThemeVarsPartial, rest?: object): ThemeVars;

18

19

interface ThemeVars extends ThemeVarsBase, ThemeVarsColors {

20

/** Base theme type - determines default color palette */

21

base: 'light' | 'dark';

22

23

/** Brand colors */

24

colorPrimary: string;

25

colorSecondary: string;

26

27

/** Application background colors */

28

appBg: string;

29

appContentBg: string;

30

appPreviewBg: string;

31

appBorderColor: string;

32

appBorderRadius: number;

33

34

/** Typography */

35

fontBase: string;

36

fontCode: string;

37

38

/** Text colors */

39

textColor: string;

40

textInverseColor: string;

41

textMutedColor: string;

42

43

/** Interactive element colors */

44

barTextColor: string;

45

barHoverColor: string;

46

barSelectedColor: string;

47

barBg: string;

48

49

/** Input colors */

50

inputBg: string;

51

inputBorder: string;

52

inputTextColor: string;

53

inputBorderRadius: number;

54

55

/** Layout dimensions */

56

layoutMargin: number;

57

addonActionsTheme: string;

58

}

59

60

type ThemeVarsPartial = Partial<ThemeVars>;

61

```

62

63

**Usage Example:**

64

65

```typescript

66

import { create } from "storybook/theming";

67

68

// Create custom light theme

69

const customLightTheme = create({

70

base: "light",

71

colorPrimary: "#FF6B6B",

72

colorSecondary: "#4ECDC4",

73

appBg: "#F8F9FA",

74

appContentBg: "#FFFFFF",

75

appBorderColor: "#E9ECEF",

76

fontBase: '"Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',

77

textColor: "#333333",

78

barTextColor: "#666666",

79

});

80

81

// Create custom dark theme

82

const customDarkTheme = create({

83

base: "dark",

84

colorPrimary: "#FF6B6B",

85

colorSecondary: "#4ECDC4",

86

appBg: "#1A1A1A",

87

appContentBg: "#2A2A2A",

88

appBorderColor: "#3A3A3A",

89

textColor: "#FFFFFF",

90

barTextColor: "#CCCCCC",

91

});

92

93

// Export for use in manager configuration

94

export { customLightTheme, customDarkTheme };

95

```

96

97

### Pre-built Themes

98

99

Access to Storybook's built-in themes for quick setup.

100

101

```typescript { .api }

102

/**

103

* Pre-built theme objects

104

*/

105

const themes: {

106

/** Light theme with default Storybook styling */

107

light: ThemeVars;

108

/** Dark theme with default Storybook styling */

109

dark: ThemeVars;

110

/** Alias for light theme */

111

normal: ThemeVars;

112

};

113

```

114

115

**Usage Example:**

116

117

```typescript

118

import { themes } from "storybook/theming";

119

120

// Use built-in themes directly

121

export const lightTheme = themes.light;

122

export const darkTheme = themes.dark;

123

124

// Extend built-in themes

125

export const customTheme = {

126

...themes.light,

127

colorPrimary: "#FF6B6B",

128

brandTitle: "My Custom Storybook",

129

brandUrl: "https://example.com",

130

};

131

```

132

133

### Global Styles

134

135

Create global CSS styles for Storybook's UI components.

136

137

```typescript { .api }

138

/**

139

* Create global styles for Storybook UI

140

* @param theme - Theme object to base styles on

141

* @returns Emotion Global component

142

*/

143

function createGlobal(theme?: ThemeVars): React.ComponentType;

144

145

/**

146

* Create CSS reset styles

147

* @returns Emotion Global component with reset styles

148

*/

149

function createReset(): React.ComponentType;

150

```

151

152

**Usage Example:**

153

154

```typescript

155

import { createGlobal, createReset, themes } from "storybook/theming";

156

157

// Create global styles component

158

const GlobalStyles = createGlobal(themes.light);

159

160

// Create reset styles component

161

const ResetStyles = createReset();

162

163

// Use in manager or preview

164

export const decorators = [

165

(Story) => (

166

<>

167

<ResetStyles />

168

<GlobalStyles />

169

<Story />

170

</>

171

),

172

];

173

```

174

175

### Color Utilities

176

177

Utility functions for color manipulation within themes.

178

179

```typescript { .api }

180

/**

181

* Lighten a color by a percentage

182

* @param color - Base color (hex, rgb, hsl, or named)

183

* @param amount - Amount to lighten (0-1)

184

* @returns Lightened color string

185

*/

186

function lighten(color: string, amount?: number): string;

187

188

/**

189

* Darken a color by a percentage

190

* @param color - Base color (hex, rgb, hsl, or named)

191

* @param amount - Amount to darken (0-1)

192

* @returns Darkened color string

193

*/

194

function darken(color: string, amount?: number): string;

195

```

196

197

**Usage Example:**

198

199

```typescript

200

import { create, lighten, darken } from "storybook/theming";

201

202

const baseColor = "#3B82F6";

203

204

const theme = create({

205

base: "light",

206

colorPrimary: baseColor,

207

colorSecondary: lighten(baseColor, 0.2),

208

appBorderColor: lighten(baseColor, 0.8),

209

barHoverColor: darken(baseColor, 0.1),

210

});

211

```

212

213

## Emotion CSS-in-JS Integration

214

215

Storybook's theming system is built on Emotion and re-exports key utilities for custom styling.

216

217

### Styled Components

218

219

```typescript { .api }

220

/**

221

* Create styled React components with theme support

222

*/

223

const styled: StyledInterface;

224

225

interface StyledInterface {

226

<T extends React.ComponentType<any>>(component: T): StyledComponent<T>;

227

[key: string]: StyledComponent<any>; // HTML elements (div, span, etc.)

228

}

229

230

type StyledComponent<T> = (

231

template: TemplateStringsArray,

232

...args: Array<string | number | ((props: any) => string | number)>

233

) => React.ComponentType<T>;

234

```

235

236

### CSS and Keyframes

237

238

```typescript { .api }

239

/**

240

* Create CSS styles with template literals

241

* @param template - CSS template string

242

* @param args - Interpolated values or functions

243

* @returns Emotion CSS object

244

*/

245

function css(

246

template: TemplateStringsArray,

247

...args: Array<string | number | ((props: any) => string | number)>

248

): string;

249

250

/**

251

* Create CSS keyframe animations

252

* @param template - Keyframes template string

253

* @returns Animation name string

254

*/

255

function keyframes(template: TemplateStringsArray): string;

256

```

257

258

### Theme Provider and Hooks

259

260

```typescript { .api }

261

/**

262

* Provide theme context to child components

263

*/

264

const ThemeProvider: React.ComponentType<{

265

theme: ThemeVars;

266

children: React.ReactNode;

267

}>;

268

269

/**

270

* Access theme from context within components

271

* @returns Current theme object

272

*/

273

function useTheme(): ThemeVars;

274

275

/**

276

* HOC to inject theme as prop

277

* @param Component - React component to wrap

278

* @returns Component with theme prop injected

279

*/

280

function withTheme<P>(

281

Component: React.ComponentType<P & { theme: ThemeVars }>

282

): React.ComponentType<P>;

283

```

284

285

### Global and Cache Components

286

287

```typescript { .api }

288

/**

289

* Inject global styles into document head

290

*/

291

const Global: React.ComponentType<{

292

styles: string | ((theme: ThemeVars) => string);

293

}>;

294

295

/**

296

* Apply CSS class names conditionally

297

*/

298

const ClassNames: React.ComponentType<{

299

children: (cx: (...classNames: (string | false | undefined)[]) => string) => React.ReactNode;

300

}>;

301

302

/**

303

* Provide Emotion cache context

304

*/

305

const CacheProvider: React.ComponentType<{

306

value: EmotionCache;

307

children: React.ReactNode;

308

}>;

309

310

/**

311

* Create Emotion cache instance

312

* @param options - Cache configuration options

313

* @returns Emotion cache instance

314

*/

315

function createCache(options: CacheOptions): EmotionCache;

316

317

interface CacheOptions {

318

key: string;

319

container?: HTMLElement;

320

nonce?: string;

321

prepend?: boolean;

322

stylisPlugins?: any[];

323

}

324

```

325

326

**Usage Example:**

327

328

```typescript

329

import {

330

styled,

331

css,

332

keyframes,

333

ThemeProvider,

334

useTheme,

335

Global

336

} from "storybook/theming";

337

338

// Styled component with theme

339

const StyledButton = styled.button`

340

background: ${(props) => props.theme.colorPrimary};

341

color: ${(props) => props.theme.textInverseColor};

342

border: none;

343

border-radius: ${(props) => props.theme.appBorderRadius}px;

344

padding: 8px 16px;

345

font-family: ${(props) => props.theme.fontBase};

346

347

&:hover {

348

background: ${(props) => lighten(props.theme.colorPrimary, 0.1)};

349

}

350

`;

351

352

// CSS styles

353

const cardStyles = css`

354

background: white;

355

border-radius: 4px;

356

box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

357

padding: 16px;

358

`;

359

360

// Keyframe animation

361

const fadeIn = keyframes`

362

from { opacity: 0; }

363

to { opacity: 1; }

364

`;

365

366

// Component using theme hook

367

const ThemedComponent = () => {

368

const theme = useTheme();

369

370

return (

371

<div style={{ color: theme.textColor, background: theme.appBg }}>

372

Themed content

373

</div>

374

);

375

};

376

377

// Usage with ThemeProvider

378

export const ThemedStory: Story = {

379

decorators: [

380

(Story) => (

381

<ThemeProvider theme={customTheme}>

382

<Global styles={`body { margin: 0; }`} />

383

<Story />

384

</ThemeProvider>

385

),

386

],

387

};

388

```

389

390

## Manager Configuration

391

392

Configure themes for Storybook's manager UI.

393

394

**Usage Example (.storybook/manager.js):**

395

396

```typescript

397

import { addons } from '@storybook/manager-api';

398

import { create } from 'storybook/theming';

399

400

const theme = create({

401

base: 'light',

402

brandTitle: 'My Custom Storybook',

403

brandUrl: 'https://example.com',

404

brandImage: 'https://example.com/logo.png',

405

brandTarget: '_self',

406

407

colorPrimary: '#FF6B6B',

408

colorSecondary: '#4ECDC4',

409

410

// UI colors

411

appBg: '#F8F9FA',

412

appContentBg: '#FFFFFF',

413

appBorderColor: '#E9ECEF',

414

appBorderRadius: 4,

415

416

// Typography

417

fontBase: '"Nunito Sans", sans-serif',

418

fontCode: 'Monaco, "Courier New", monospace',

419

420

// Text colors

421

textColor: '#333333',

422

textInverseColor: '#FFFFFF',

423

424

// Toolbar colors

425

barTextColor: '#666666',

426

barSelectedColor: '#FF6B6B',

427

barBg: '#FFFFFF',

428

429

// Form colors

430

inputBg: '#FFFFFF',

431

inputBorder: '#E9ECEF',

432

inputTextColor: '#333333',

433

inputBorderRadius: 4,

434

});

435

436

addons.setConfig({

437

theme,

438

});

439

```

440

441

## Advanced Theming Patterns

442

443

### Dynamic Theme Switching

444

445

```typescript

446

import { useState } from 'react';

447

import { ThemeProvider, themes } from 'storybook/theming';

448

449

export const DynamicThemeStory: Story = {

450

render: () => {

451

const [isDark, setIsDark] = useState(false);

452

const currentTheme = isDark ? themes.dark : themes.light;

453

454

return (

455

<ThemeProvider theme={currentTheme}>

456

<button onClick={() => setIsDark(!isDark)}>

457

Switch to {isDark ? 'Light' : 'Dark'} Theme

458

</button>

459

<ThemedComponent />

460

</ThemeProvider>

461

);

462

},

463

};

464

```

465

466

### CSS Custom Properties Integration

467

468

```typescript

469

const cssVariableTheme = create({

470

base: 'light',

471

colorPrimary: 'var(--primary-color, #3B82F6)',

472

colorSecondary: 'var(--secondary-color, #10B981)',

473

appBg: 'var(--app-bg, #FFFFFF)',

474

});

475

```