Date: September 22, 2024
In modern Angular development, creating reusable component libraries is key to maintaining consistency and speeding up development across multiple projects. But how do you build, document, and publish such a library efficiently?
This tutorial walks you through creating a custom Angular component library from scratch, integrating Storybook for interactive documentation, and preparing the library for publishing and reuse.
Why Build a Component Library?
- Reusability: Share UI components across projects and teams.
- Consistency: Ensure consistent styling and behavior.
- Maintainability: Centralize updates and fixes.
- Documentation: Provide clear, interactive usage docs via Storybook.
Step 1: Setting Up Your Angular Workspace
Start with an Nx or Angular CLI workspace:
ng new angular-component-library --create-application=false
cd angular-component-library
Create a new Angular library:
ng generate library ui-components
This creates a library project under projects/ui-components
with boilerplate.
Step 2: Building Your First Component
Navigate to your library folder:
cd projects/ui-components/src/lib
Create a simple reusable button component:
// button.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'ui-button',
template: `
<button [ngClass]="type" [disabled]="disabled">
<ng-content></ng-content>
</button>
`,
styles: [
`
button {
font-size: 1rem;
padding: 0.5rem 1rem;
border-radius: 4px;
border: none;
cursor: pointer;
}
.primary {
background-color: #007bff;
color: white;
}
.secondary {
background-color: #6c757d;
color: white;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
`,
],
})
export class ButtonComponent {
@Input() type: 'primary' | 'secondary' = 'primary';
@Input() disabled = false;
}
Export this component in the ui-components.module.ts
:
@NgModule({
declarations: [ButtonComponent],
exports: [ButtonComponent],
})
export class UiComponentsModule {}
Step 3: Adding Storybook for Interactive Documentation
Install Storybook:
npx sb init --type angular
Configure Storybook to load your library components. In .storybook/main.js
:
module.exports = {
stories: ['../projects/ui-components/src/lib/**/*.stories.ts'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
};
Create a Storybook story for your button component:
// button.component.stories.ts
import { Meta, Story } from '@storybook/angular';
import { ButtonComponent } from './button.component';
export default {
title: 'UI/Button',
component: ButtonComponent,
} as Meta;
const Template: Story<ButtonComponent> = (args) => ({
props: args,
template: `<ui-button [type]="type" [disabled]="disabled">Button</ui-button>`,
});
export const Primary = Template.bind({});
Primary.args = {
type: 'primary',
disabled: false,
};
export const Disabled = Template.bind({});
Disabled.args = {
type: 'primary',
disabled: true,
};
export const Secondary = Template.bind({});
Secondary.args = {
type: 'secondary',
disabled: false,
};
Run Storybook to see your button variants live:
npm run storybook
Step 4: Testing Your Components
Use Angular testing utilities to create unit tests:
// button.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ButtonComponent } from './button.component';
describe('ButtonComponent', () => {
let component: ButtonComponent;
let fixture: ComponentFixture<ButtonComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ButtonComponent],
}).compileComponents();
fixture = TestBed.createComponent(ButtonComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should disable button when disabled is true', () => {
component.disabled = true;
fixture.detectChanges();
const button: HTMLButtonElement = fixture.nativeElement.querySelector('button');
expect(button.disabled).toBeTrue();
});
});
Step 5: Building and Publishing the Library
Build your Angular library:
ng build ui-components
This outputs your library in dist/ui-components
.
To publish to npm:
- Make sure your
package.json
insidedist/ui-components
is configured with name, version, and metadata. - Login to npm:
npm login
- Publish your package:
cd dist/ui-components
npm publish
Step 6: Consuming Your Library in an App
In any Angular app, install your published library:
npm install your-library-name
Import the module in your app:
import { UiComponentsModule } from 'your-library-name';
@NgModule({
imports: [UiComponentsModule],
})
export class AppModule {}
Use the button component:
<ui-button type="primary">Click Me</ui-button>
Summary
By building your own Angular component library with Storybook integration, you achieve:
- Reusable, testable, and well-documented UI components
- Faster development with shared design patterns
- Professional documentation that fosters collaboration