Storybook for Angular: Develop, document, and test UI components in isolation
—
Angular-specific decorators for configuring module metadata, application configuration, and component wrapping in stories.
Decorator for providing Angular module metadata to stories, including imports, declarations, providers, and schemas.
/**
* Decorator for Angular module metadata configuration
* @param metadata - Partial NgModuleMetadata configuration
* @returns Decorator function for stories
*/
declare function moduleMetadata<TArgs = any>(
metadata: Partial<NgModuleMetadata>
): DecoratorFunction<AngularRenderer, TArgs>;
interface NgModuleMetadata {
/** List of components, directives, and pipes that belong to your component */
declarations?: any[];
entryComponents?: any[];
/**
* List of modules that should be available to the root Storybook Component and all its children.
* For application providers or forRoot() patterns, use applicationConfig decorator instead.
*/
imports?: any[];
schemas?: any[];
/**
* List of providers that should be available on the root component and all its children.
* Use applicationConfig decorator for environment and application-wide providers.
*/
providers?: Provider[];
}Usage Examples:
Basic module configuration:
import { moduleMetadata } from "@storybook/angular";
import { CommonModule } from "@angular/common";
import { FormsModule } from "@angular/forms";
import { ButtonComponent } from "./button.component";
export default {
title: "Example/Button",
component: ButtonComponent,
decorators: [
moduleMetadata({
imports: [CommonModule, FormsModule],
declarations: [ButtonComponent],
}),
],
};With providers:
import { moduleMetadata } from "@storybook/angular";
import { HttpClientModule } from "@angular/common/http";
import { DataService } from "./data.service";
export default {
title: "Example/DataComponent",
component: DataComponent,
decorators: [
moduleMetadata({
imports: [HttpClientModule],
providers: [DataService],
}),
],
};With schemas for custom elements:
import { moduleMetadata } from "@storybook/angular";
import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
export default {
title: "Example/CustomElement",
component: CustomElementComponent,
decorators: [
moduleMetadata({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}),
],
};Multiple decorators (metadata merges):
const baseDecorator = moduleMetadata({
imports: [CommonModule],
});
const extendedDecorator = moduleMetadata({
imports: [FormsModule],
providers: [MyService],
});
export const Enhanced: Story = {
decorators: [baseDecorator, extendedDecorator],
// Final metadata will include: CommonModule, FormsModule, and MyService
};Decorator for setting application-level configuration options available during Angular bootstrap.
/**
* Decorator to set the config options which are available during the application bootstrap operation
* @param config - Set of config options available during the application bootstrap operation
* @returns Decorator function for stories
*/
declare function applicationConfig<TArgs = any>(
config: ApplicationConfig
): DecoratorFunction<AngularRenderer, TArgs>;
interface ApplicationConfig {
providers?: Provider[];
}Usage Examples:
With routing configuration:
import { applicationConfig } from "@storybook/angular";
import { provideRouter } from "@angular/router";
import { routes } from "./app.routes";
export default {
title: "Example/RoutedComponent",
component: RoutedComponent,
decorators: [
applicationConfig({
providers: [provideRouter(routes)],
}),
],
};With HTTP client:
import { applicationConfig } from "@storybook/angular";
import { provideHttpClient } from "@angular/common/http";
export default {
title: "Example/ApiComponent",
component: ApiComponent,
decorators: [
applicationConfig({
providers: [provideHttpClient()],
}),
],
};With animations:
import { applicationConfig } from "@storybook/angular";
import { provideAnimations } from "@angular/platform-browser/animations";
export default {
title: "Example/AnimatedComponent",
component: AnimatedComponent,
decorators: [
applicationConfig({
providers: [provideAnimations()],
}),
],
};Combined with moduleMetadata:
import { applicationConfig, moduleMetadata } from "@storybook/angular";
import { provideRouter } from "@angular/router";
import { CommonModule } from "@angular/common";
export default {
title: "Example/ComplexComponent",
component: ComplexComponent,
decorators: [
// Application-level configuration
applicationConfig({
providers: [provideRouter([])],
}),
// Module-level configuration
moduleMetadata({
imports: [CommonModule],
}),
],
};Decorator for wrapping stories with additional components or custom template wrappers.
/**
* Decorator for wrapping components with additional elements or custom templates
* @param element - Angular component type or template function
* @param props - Static props object or function returning props based on story context
* @returns Decorator function for stories
*/
declare function componentWrapperDecorator<TArgs = any>(
element: Type<unknown> | ((story: string) => string),
props?: ICollection | ((storyContext: StoryContext<AngularRenderer, TArgs>) => ICollection)
): DecoratorFunction<AngularRenderer, TArgs>;
interface ICollection {
[p: string]: any;
}Usage Examples:
Wrap with Angular component:
import { componentWrapperDecorator } from "@storybook/angular";
import { CardComponent } from "./card.component";
export default {
title: "Example/Button",
component: ButtonComponent,
decorators: [
componentWrapperDecorator(CardComponent, {
title: "Button Demo",
padding: true,
}),
],
};Wrap with custom template function:
import { componentWrapperDecorator } from "@storybook/angular";
export default {
title: "Example/Icon",
component: IconComponent,
decorators: [
componentWrapperDecorator((story) => `
<div style="padding: 20px; background: #f5f5f5; border-radius: 8px;">
<h3>Icon Preview</h3>
${story}
</div>
`),
],
};Dynamic props based on story context:
import { componentWrapperDecorator } from "@storybook/angular";
import { ThemeWrapperComponent } from "./theme-wrapper.component";
export default {
title: "Example/ThemedComponent",
component: ThemedComponent,
decorators: [
componentWrapperDecorator(
ThemeWrapperComponent,
(storyContext) => ({
theme: storyContext.parameters.theme || "light",
showBorder: storyContext.args.bordered,
})
),
],
};Multiple wrapper decorators:
const cardWrapper = componentWrapperDecorator(CardComponent);
const containerWrapper = componentWrapperDecorator(
(story) => `<div class="container">${story}</div>`
);
export const Nested: Story = {
decorators: [containerWrapper, cardWrapper],
// Story will be wrapped: container > card > component
};Decorators are applied in reverse order (last decorator wraps the innermost content):
export default {
title: "Example/Component",
component: MyComponent,
decorators: [
// Applied third (outermost)
componentWrapperDecorator((story) => `<div class="outer">${story}</div>`),
// Applied second (middle)
moduleMetadata({ imports: [CommonModule] }),
// Applied first (innermost, around the component)
applicationConfig({ providers: [MyService] }),
],
};moduleMetadata for Angular modules, pipes, directives, and component-level providersapplicationConfig for application-wide providers like routing, HTTP client, animationsapplicationConfig over NgModule patterns when possiblecomponentWrapperDecorator for layout, theming, or presentation concernsInstall with Tessl CLI
npx tessl i tessl/npm-storybook--angular