Storybook for Angular: Develop, document, and test UI components in isolation
—
Framework-specific configuration options and Storybook main configuration utilities for Angular projects.
Main configuration interface for Storybook Angular projects, extending base Storybook configuration with Angular-specific options.
/**
* The interface for Storybook configuration in `main.ts` files for Angular projects
*/
interface StorybookConfig extends Omit<
StorybookConfigBase,
keyof StorybookConfigWebpack | keyof StorybookConfigFramework
>, StorybookConfigWebpack, StorybookConfigFramework {
framework: '@storybook/angular' | {
name: '@storybook/angular';
options: FrameworkOptions;
};
}
interface StorybookConfigFramework {
framework:
| '@storybook/angular'
| {
name: '@storybook/angular';
options: FrameworkOptions;
};
core?: StorybookConfigBase['core'] & {
builder?:
| '@storybook/builder-webpack5'
| {
name: '@storybook/builder-webpack5';
options: BuilderOptions;
};
};
typescript?: Partial<TypescriptOptionsBuilder & TypescriptOptionsReact> &
StorybookConfigBase['typescript'];
}Basic Configuration Example:
// .storybook/main.ts
import type { StorybookConfig } from '@storybook/angular';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: '@storybook/angular',
typescript: {
check: false,
reactDocgen: 'react-docgen-typescript',
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
},
},
};
export default config;Angular-specific framework configuration options.
/**
* Options for configuring the Angular framework integration
*/
interface FrameworkOptions extends AngularOptions {
/** Builder-specific options for webpack5 */
builder?: BuilderOptions;
}
interface AngularOptions {
/** Enable Angular Ivy renderer (default: true in Angular 12+) */
enableIvy?: boolean;
}Configuration with Framework Options:
// .storybook/main.ts
import type { StorybookConfig } from '@storybook/angular';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: ['@storybook/addon-essentials'],
framework: {
name: '@storybook/angular',
options: {
enableIvy: true,
builder: {
useSWC: true,
},
},
},
core: {
builder: {
name: '@storybook/builder-webpack5',
options: {
fsCache: true,
lazyCompilation: true,
},
},
},
};
export default config;Utility function for defining Storybook main configuration with type safety.
/**
* Helper function for defining main configuration with type safety
* @param config - Storybook configuration object
* @returns Typed configuration object
*/
declare function defineMain(config: StorybookConfig): StorybookConfig;Usage Example:
// .storybook/main.ts
import { defineMain } from '@storybook/angular/node';
export default defineMain({
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: '@storybook/angular',
typescript: {
check: false,
},
// Full type safety and IntelliSense support
});Minimal configuration for a standard Angular project:
import type { StorybookConfig } from '@storybook/angular';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
],
framework: '@storybook/angular',
};
export default config;Configuration for projects using Angular Material:
import type { StorybookConfig } from '@storybook/angular';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-docs',
],
framework: '@storybook/angular',
staticDirs: ['../src/assets'],
webpackFinal: async (config) => {
// Custom webpack configuration for Angular Material
config.module.rules.push({
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
});
return config;
},
};
export default config;Advanced webpack customization:
import type { StorybookConfig } from '@storybook/angular';
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/angular',
options: {
builder: {
useSWC: true,
},
},
},
core: {
builder: {
name: '@storybook/builder-webpack5',
options: {
fsCache: true,
lazyCompilation: true,
},
},
},
webpackFinal: async (config) => {
// Add TypeScript path mapping
config.resolve.plugins = [
...(config.resolve.plugins || []),
new TsconfigPathsPlugin({
configFile: path.resolve(__dirname, '../tsconfig.json'),
}),
];
// Handle Angular specific loaders
config.module.rules.push({
test: /\.html$/,
loader: 'html-loader',
options: {
minimize: true,
},
});
return config;
},
};
export default config;Configuration for Angular monorepo (Nx, Lerna, etc.):
import type { StorybookConfig } from '@storybook/angular';
import { join, dirname } from 'path';
function getAbsolutePath(value: string): any {
return dirname(require.resolve(join(value, 'package.json')));
}
const config: StorybookConfig = {
stories: [
'../../../libs/**/*.stories.@(js|jsx|ts|tsx|mdx)',
'../src/**/*.stories.@(js|jsx|ts|tsx|mdx)',
],
addons: [
getAbsolutePath('@storybook/addon-links'),
getAbsolutePath('@storybook/addon-essentials'),
getAbsolutePath('@storybook/addon-interactions'),
],
framework: {
name: getAbsolutePath('@storybook/angular'),
options: {},
},
typescript: {
check: false,
reactDocgen: 'react-docgen-typescript',
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
},
},
};
export default config;Configuration optimized for large Angular projects:
import type { StorybookConfig } from '@storybook/angular';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-essentials',
{
name: '@storybook/addon-docs',
options: {
transcludeMarkdown: true,
},
},
],
framework: {
name: '@storybook/angular',
options: {
enableIvy: true,
builder: {
useSWC: true,
fsCache: true,
},
},
},
core: {
builder: {
name: '@storybook/builder-webpack5',
options: {
fsCache: true,
lazyCompilation: true,
},
},
disableTelemetry: true,
},
typescript: {
check: false, // Disable type checking for faster builds
reactDocgen: false, // Disable docgen for faster builds
},
features: {
storyStoreV7: true,
argTypeTargetsV7: true,
},
};
export default config;interface AngularTypeScriptConfig {
typescript?: {
/** Enable/disable TypeScript type checking */
check?: boolean;
/** Skip TypeScript compilation in favor of Angular's compiler */
skipCompiler?: boolean;
/** React docgen configuration (inherited from webpack builder) */
reactDocgen?: 'react-docgen-typescript' | 'react-docgen' | false;
/** Options for react-docgen-typescript */
reactDocgenTypescriptOptions?: {
shouldExtractLiteralValuesFromEnum?: boolean;
propFilter?: (prop: any) => boolean;
};
};
}TypeScript Configuration Example:
const config: StorybookConfig = {
// ... other options
typescript: {
check: true,
skipCompiler: false,
reactDocgen: 'react-docgen-typescript',
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) => {
if (prop.parent) {
return !/node_modules/.test(prop.parent.fileName);
}
return true;
},
},
},
};The Angular framework automatically includes necessary presets:
// Automatically included presets:
const presets = [
require.resolve('./server/framework-preset-angular-cli'),
require.resolve('./server/framework-preset-angular-ivy'),
];Automatic preview configuration:
// Automatically configured preview annotations:
const previewAnnotations = [
'@storybook/angular/dist/client/config.mjs',
// Conditionally added based on options:
'@storybook/angular/dist/client/preview-prod.mjs', // if enableProdMode
'@storybook/angular/dist/client/docs/config.mjs', // if docs enabled
];const config: StorybookConfig = {
// ... base config
core: {
builder: {
name: '@storybook/builder-webpack5',
options: {
lazyCompilation: true,
fsCache: true,
},
},
},
typescript: {
check: true, // Enable checking in dev
},
};const config: StorybookConfig = {
// ... base config
core: {
disableTelemetry: true,
builder: {
name: '@storybook/builder-webpack5',
options: {
fsCache: false, // Disable for reproducible builds
},
},
},
typescript: {
check: false, // Disable checking for faster CI builds
},
};Install with Tessl CLI
npx tessl i tessl/npm-storybook--angular