CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-storybook--angular

Storybook for Angular: Develop, document, and test UI components in isolation

Pending
Overview
Eval results
Files

decorators.mddocs/

Angular Decorators

Angular-specific decorators for configuring module metadata, application configuration, and component wrapping in stories.

Capabilities

moduleMetadata Decorator

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
};

applicationConfig Decorator

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],
    }),
  ],
};

componentWrapperDecorator

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
};

Decorator Composition and Order

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] }),
  ],
};

Best Practices

Module Metadata

  • Use moduleMetadata for Angular modules, pipes, directives, and component-level providers
  • Place shared imports in global decorators (preview.ts) when used across many stories
  • Keep module metadata close to the component requirements

Application Config

  • Use applicationConfig for application-wide providers like routing, HTTP client, animations
  • Configure once at the story or meta level rather than per individual story
  • Prefer standalone components and applicationConfig over NgModule patterns when possible

Component Wrapper

  • Use componentWrapperDecorator for layout, theming, or presentation concerns
  • Keep wrapper logic simple and focused on presentation
  • Consider performance implications of complex wrapper components

Install with Tessl CLI

npx tessl i tessl/npm-storybook--angular

docs

cli-builders.md

decorators.md

framework-config.md

index.md

portable-stories.md

story-types.md

template-utilities.md

tile.json