or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

css-class-theming.mdcustom-decorators.mddata-attribute-theming.mdindex.mdjsx-provider-theming.md

jsx-provider-theming.mddocs/

0

# JSX Provider-Based Theming

1

2

Theme switching using JSX provider components and theme objects. This approach is designed for component libraries like styled-components, emotion, Material-UI, and other CSS-in-JS solutions that use theme providers.

3

4

## Capabilities

5

6

### withThemeFromJSXProvider

7

8

Creates a decorator that wraps stories with a theme provider component and passes theme objects to the provider.

9

10

```typescript { .api }

11

/**

12

* Creates a decorator for JSX provider-based theme switching

13

* @param config - Configuration object specifying provider, themes, and options

14

* @returns Storybook decorator function

15

*/

16

function withThemeFromJSXProvider<TRenderer extends Renderer = any>(

17

config: ProviderStrategyConfiguration

18

): DecoratorFunction<TRenderer>;

19

20

interface ProviderStrategyConfiguration {

21

/** JSX provider component that accepts a theme prop */

22

Provider?: any;

23

/** Global styles component to render alongside the provider */

24

GlobalStyles?: any;

25

/** Name of the default theme */

26

defaultTheme?: string;

27

/** Mapping of theme names to theme objects */

28

themes?: Record<string, any>;

29

}

30

```

31

32

**Usage Examples:**

33

34

```typescript

35

import { withThemeFromJSXProvider } from '@storybook/addon-themes';

36

import { ThemeProvider } from 'styled-components';

37

import { lightTheme, darkTheme } from './themes';

38

39

// Styled-components example

40

export const decorators = [

41

withThemeFromJSXProvider({

42

themes: {

43

light: lightTheme,

44

dark: darkTheme,

45

},

46

defaultTheme: 'light',

47

Provider: ThemeProvider,

48

}),

49

];

50

51

// Material-UI example

52

import { ThemeProvider, createTheme } from '@mui/material/styles';

53

import CssBaseline from '@mui/material/CssBaseline';

54

55

const lightTheme = createTheme({

56

palette: {

57

mode: 'light',

58

},

59

});

60

61

const darkTheme = createTheme({

62

palette: {

63

mode: 'dark',

64

},

65

});

66

67

export const decorators = [

68

withThemeFromJSXProvider({

69

themes: {

70

light: lightTheme,

71

dark: darkTheme,

72

},

73

defaultTheme: 'light',

74

Provider: ThemeProvider,

75

GlobalStyles: CssBaseline,

76

}),

77

];

78

79

// Emotion example

80

import { ThemeProvider } from '@emotion/react';

81

import { Global, css } from '@emotion/react';

82

83

const GlobalStyles = () => (

84

<Global

85

styles={css`

86

body {

87

margin: 0;

88

font-family: -apple-system, BlinkMacSystemFont, sans-serif;

89

}

90

`}

91

/>

92

);

93

94

export const decorators = [

95

withThemeFromJSXProvider({

96

themes: {

97

brand: { primary: '#007bff', secondary: '#6c757d' },

98

corporate: { primary: '#28a745', secondary: '#17a2b8' },

99

},

100

defaultTheme: 'brand',

101

Provider: ThemeProvider,

102

GlobalStyles: GlobalStyles,

103

}),

104

];

105

```

106

107

## Implementation Details

108

109

### Provider Wrapping

110

111

The decorator automatically:

112

- Wraps each story with the specified Provider component

113

- Passes the selected theme object as the `theme` prop

114

- Renders GlobalStyles component alongside the provider

115

- Handles theme switching by passing different theme objects

116

117

### Theme Object Structure

118

119

Theme objects can have any structure that your styling library expects:

120

121

```typescript

122

// Styled-components theme example

123

const lightTheme = {

124

colors: {

125

primary: '#007bff',

126

secondary: '#6c757d',

127

background: '#ffffff',

128

text: '#212529',

129

},

130

spacing: {

131

small: '8px',

132

medium: '16px',

133

large: '24px',

134

},

135

breakpoints: {

136

mobile: '768px',

137

desktop: '1024px',

138

},

139

};

140

141

// Material-UI theme example (using createTheme)

142

const muiTheme = createTheme({

143

palette: {

144

mode: 'light',

145

primary: {

146

main: '#1976d2',

147

},

148

secondary: {

149

main: '#dc004e',

150

},

151

},

152

typography: {

153

fontFamily: 'Roboto, Arial, sans-serif',

154

},

155

});

156

```

157

158

### Single Theme Usage

159

160

When only one theme is provided, the decorator still wraps stories with the provider:

161

162

```typescript

163

export const decorators = [

164

withThemeFromJSXProvider({

165

themes: {

166

default: singleTheme,

167

},

168

Provider: ThemeProvider,

169

}),

170

];

171

```

172

173

### GlobalStyles Integration

174

175

The GlobalStyles component is rendered alongside the provider, perfect for CSS resets and global styles:

176

177

```typescript

178

// Styled-components GlobalStyle

179

import { createGlobalStyle } from 'styled-components';

180

181

const GlobalStyle = createGlobalStyle`

182

body {

183

margin: 0;

184

font-family: ${props => props.theme.fonts.primary};

185

background-color: ${props => props.theme.colors.background};

186

color: ${props => props.theme.colors.text};

187

}

188

`;

189

190

export const decorators = [

191

withThemeFromJSXProvider({

192

themes: { light: lightTheme, dark: darkTheme },

193

defaultTheme: 'light',

194

Provider: ThemeProvider,

195

GlobalStyles: GlobalStyle,

196

}),

197

];

198

```

199

200

## Framework Integration

201

202

### Styled-Components

203

204

```typescript

205

import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';

206

207

const GlobalStyle = createGlobalStyle`

208

body {

209

background-color: ${props => props.theme.background};

210

color: ${props => props.theme.text};

211

}

212

`;

213

214

const themes = {

215

light: {

216

background: '#ffffff',

217

text: '#000000',

218

primary: '#007bff',

219

},

220

dark: {

221

background: '#121212',

222

text: '#ffffff',

223

primary: '#66aaff',

224

},

225

};

226

227

export const decorators = [

228

withThemeFromJSXProvider({

229

themes,

230

defaultTheme: 'light',

231

Provider: ThemeProvider,

232

GlobalStyles: GlobalStyle,

233

}),

234

];

235

```

236

237

### Emotion

238

239

```typescript

240

import { ThemeProvider } from '@emotion/react';

241

import { Global, css } from '@emotion/react';

242

243

const GlobalStyles = ({ theme }) => (

244

<Global

245

styles={css`

246

body {

247

background-color: ${theme.background};

248

color: ${theme.text};

249

}

250

`}

251

/>

252

);

253

254

export const decorators = [

255

withThemeFromJSXProvider({

256

themes: emotionThemes,

257

defaultTheme: 'light',

258

Provider: ThemeProvider,

259

GlobalStyles: GlobalStyles,

260

}),

261

];

262

```

263

264

### Material-UI (MUI)

265

266

```typescript

267

import { ThemeProvider, createTheme } from '@mui/material/styles';

268

import CssBaseline from '@mui/material/CssBaseline';

269

270

const lightTheme = createTheme({

271

palette: { mode: 'light' },

272

});

273

274

const darkTheme = createTheme({

275

palette: { mode: 'dark' },

276

});

277

278

export const decorators = [

279

withThemeFromJSXProvider({

280

themes: {

281

light: lightTheme,

282

dark: darkTheme,

283

},

284

defaultTheme: 'light',

285

Provider: ThemeProvider,

286

GlobalStyles: CssBaseline,

287

}),

288

];

289

```