0
# Angular Decorators
1
2
Angular-specific decorators for configuring module metadata, application configuration, and component wrapping in stories.
3
4
## Capabilities
5
6
### moduleMetadata Decorator
7
8
Decorator for providing Angular module metadata to stories, including imports, declarations, providers, and schemas.
9
10
```typescript { .api }
11
/**
12
* Decorator for Angular module metadata configuration
13
* @param metadata - Partial NgModuleMetadata configuration
14
* @returns Decorator function for stories
15
*/
16
declare function moduleMetadata<TArgs = any>(
17
metadata: Partial<NgModuleMetadata>
18
): DecoratorFunction<AngularRenderer, TArgs>;
19
20
interface NgModuleMetadata {
21
/** List of components, directives, and pipes that belong to your component */
22
declarations?: any[];
23
entryComponents?: any[];
24
/**
25
* List of modules that should be available to the root Storybook Component and all its children.
26
* For application providers or forRoot() patterns, use applicationConfig decorator instead.
27
*/
28
imports?: any[];
29
schemas?: any[];
30
/**
31
* List of providers that should be available on the root component and all its children.
32
* Use applicationConfig decorator for environment and application-wide providers.
33
*/
34
providers?: Provider[];
35
}
36
```
37
38
**Usage Examples:**
39
40
Basic module configuration:
41
42
```typescript
43
import { moduleMetadata } from "@storybook/angular";
44
import { CommonModule } from "@angular/common";
45
import { FormsModule } from "@angular/forms";
46
import { ButtonComponent } from "./button.component";
47
48
export default {
49
title: "Example/Button",
50
component: ButtonComponent,
51
decorators: [
52
moduleMetadata({
53
imports: [CommonModule, FormsModule],
54
declarations: [ButtonComponent],
55
}),
56
],
57
};
58
```
59
60
With providers:
61
62
```typescript
63
import { moduleMetadata } from "@storybook/angular";
64
import { HttpClientModule } from "@angular/common/http";
65
import { DataService } from "./data.service";
66
67
export default {
68
title: "Example/DataComponent",
69
component: DataComponent,
70
decorators: [
71
moduleMetadata({
72
imports: [HttpClientModule],
73
providers: [DataService],
74
}),
75
],
76
};
77
```
78
79
With schemas for custom elements:
80
81
```typescript
82
import { moduleMetadata } from "@storybook/angular";
83
import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
84
85
export default {
86
title: "Example/CustomElement",
87
component: CustomElementComponent,
88
decorators: [
89
moduleMetadata({
90
schemas: [CUSTOM_ELEMENTS_SCHEMA],
91
}),
92
],
93
};
94
```
95
96
Multiple decorators (metadata merges):
97
98
```typescript
99
const baseDecorator = moduleMetadata({
100
imports: [CommonModule],
101
});
102
103
const extendedDecorator = moduleMetadata({
104
imports: [FormsModule],
105
providers: [MyService],
106
});
107
108
export const Enhanced: Story = {
109
decorators: [baseDecorator, extendedDecorator],
110
// Final metadata will include: CommonModule, FormsModule, and MyService
111
};
112
```
113
114
### applicationConfig Decorator
115
116
Decorator for setting application-level configuration options available during Angular bootstrap.
117
118
```typescript { .api }
119
/**
120
* Decorator to set the config options which are available during the application bootstrap operation
121
* @param config - Set of config options available during the application bootstrap operation
122
* @returns Decorator function for stories
123
*/
124
declare function applicationConfig<TArgs = any>(
125
config: ApplicationConfig
126
): DecoratorFunction<AngularRenderer, TArgs>;
127
128
interface ApplicationConfig {
129
providers?: Provider[];
130
}
131
```
132
133
**Usage Examples:**
134
135
With routing configuration:
136
137
```typescript
138
import { applicationConfig } from "@storybook/angular";
139
import { provideRouter } from "@angular/router";
140
import { routes } from "./app.routes";
141
142
export default {
143
title: "Example/RoutedComponent",
144
component: RoutedComponent,
145
decorators: [
146
applicationConfig({
147
providers: [provideRouter(routes)],
148
}),
149
],
150
};
151
```
152
153
With HTTP client:
154
155
```typescript
156
import { applicationConfig } from "@storybook/angular";
157
import { provideHttpClient } from "@angular/common/http";
158
159
export default {
160
title: "Example/ApiComponent",
161
component: ApiComponent,
162
decorators: [
163
applicationConfig({
164
providers: [provideHttpClient()],
165
}),
166
],
167
};
168
```
169
170
With animations:
171
172
```typescript
173
import { applicationConfig } from "@storybook/angular";
174
import { provideAnimations } from "@angular/platform-browser/animations";
175
176
export default {
177
title: "Example/AnimatedComponent",
178
component: AnimatedComponent,
179
decorators: [
180
applicationConfig({
181
providers: [provideAnimations()],
182
}),
183
],
184
};
185
```
186
187
Combined with moduleMetadata:
188
189
```typescript
190
import { applicationConfig, moduleMetadata } from "@storybook/angular";
191
import { provideRouter } from "@angular/router";
192
import { CommonModule } from "@angular/common";
193
194
export default {
195
title: "Example/ComplexComponent",
196
component: ComplexComponent,
197
decorators: [
198
// Application-level configuration
199
applicationConfig({
200
providers: [provideRouter([])],
201
}),
202
// Module-level configuration
203
moduleMetadata({
204
imports: [CommonModule],
205
}),
206
],
207
};
208
```
209
210
### componentWrapperDecorator
211
212
Decorator for wrapping stories with additional components or custom template wrappers.
213
214
```typescript { .api }
215
/**
216
* Decorator for wrapping components with additional elements or custom templates
217
* @param element - Angular component type or template function
218
* @param props - Static props object or function returning props based on story context
219
* @returns Decorator function for stories
220
*/
221
declare function componentWrapperDecorator<TArgs = any>(
222
element: Type<unknown> | ((story: string) => string),
223
props?: ICollection | ((storyContext: StoryContext<AngularRenderer, TArgs>) => ICollection)
224
): DecoratorFunction<AngularRenderer, TArgs>;
225
226
interface ICollection {
227
[p: string]: any;
228
}
229
```
230
231
**Usage Examples:**
232
233
Wrap with Angular component:
234
235
```typescript
236
import { componentWrapperDecorator } from "@storybook/angular";
237
import { CardComponent } from "./card.component";
238
239
export default {
240
title: "Example/Button",
241
component: ButtonComponent,
242
decorators: [
243
componentWrapperDecorator(CardComponent, {
244
title: "Button Demo",
245
padding: true,
246
}),
247
],
248
};
249
```
250
251
Wrap with custom template function:
252
253
```typescript
254
import { componentWrapperDecorator } from "@storybook/angular";
255
256
export default {
257
title: "Example/Icon",
258
component: IconComponent,
259
decorators: [
260
componentWrapperDecorator((story) => `
261
<div style="padding: 20px; background: #f5f5f5; border-radius: 8px;">
262
<h3>Icon Preview</h3>
263
${story}
264
</div>
265
`),
266
],
267
};
268
```
269
270
Dynamic props based on story context:
271
272
```typescript
273
import { componentWrapperDecorator } from "@storybook/angular";
274
import { ThemeWrapperComponent } from "./theme-wrapper.component";
275
276
export default {
277
title: "Example/ThemedComponent",
278
component: ThemedComponent,
279
decorators: [
280
componentWrapperDecorator(
281
ThemeWrapperComponent,
282
(storyContext) => ({
283
theme: storyContext.parameters.theme || "light",
284
showBorder: storyContext.args.bordered,
285
})
286
),
287
],
288
};
289
```
290
291
Multiple wrapper decorators:
292
293
```typescript
294
const cardWrapper = componentWrapperDecorator(CardComponent);
295
const containerWrapper = componentWrapperDecorator(
296
(story) => `<div class="container">${story}</div>`
297
);
298
299
export const Nested: Story = {
300
decorators: [containerWrapper, cardWrapper],
301
// Story will be wrapped: container > card > component
302
};
303
```
304
305
## Decorator Composition and Order
306
307
Decorators are applied in reverse order (last decorator wraps the innermost content):
308
309
```typescript
310
export default {
311
title: "Example/Component",
312
component: MyComponent,
313
decorators: [
314
// Applied third (outermost)
315
componentWrapperDecorator((story) => `<div class="outer">${story}</div>`),
316
// Applied second (middle)
317
moduleMetadata({ imports: [CommonModule] }),
318
// Applied first (innermost, around the component)
319
applicationConfig({ providers: [MyService] }),
320
],
321
};
322
```
323
324
## Best Practices
325
326
### Module Metadata
327
328
- Use `moduleMetadata` for Angular modules, pipes, directives, and component-level providers
329
- Place shared imports in global decorators (preview.ts) when used across many stories
330
- Keep module metadata close to the component requirements
331
332
### Application Config
333
334
- Use `applicationConfig` for application-wide providers like routing, HTTP client, animations
335
- Configure once at the story or meta level rather than per individual story
336
- Prefer standalone components and `applicationConfig` over `NgModule` patterns when possible
337
338
### Component Wrapper
339
340
- Use `componentWrapperDecorator` for layout, theming, or presentation concerns
341
- Keep wrapper logic simple and focused on presentation
342
- Consider performance implications of complex wrapper components