Component Development — oilmod-web
When to Use
- Creating a new component in any
libs/library - Adding a Storybook story for an existing component
- Wiring up a component's public API export
Procedure
1. Generate the Component
nx generate @nx/angular:component my-component --project=<lib> --export
Replace <lib> with the target library (core, common, datatable, drawer, form, popover).
2. Implement with Signal-Based API
@Component({
selector: 'sto-my-component',
standalone: true,
imports: [
/* Angular Material or other deps */
],
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class StoMyComponent {
// Required inputs
readonly data = input.required<MyData>();
// Optional inputs with defaults
readonly config = input<MyConfig>({});
// Outputs
readonly action = output<MyEvent>();
// Computed state
readonly derived = computed(() => transform(this.data()));
}
3. Accessibility Checklist
All components MUST meet WCAG 2.1 AA:
- Add appropriate
roleattributes viahost - Bind
aria-label,aria-disabledas needed - Support keyboard navigation (
Enter,Space,Escape) - Ensure sufficient color contrast in styles
@Component({
host: {
'role': 'button',
'[attr.aria-label]': 'ariaLabel()',
'[attr.aria-disabled]': 'disabled()',
'(keydown.enter)': 'handleKeydown($event)',
'(keydown.space)': 'handleKeydown($event)'
}
})
4. Create a Storybook Story
Follow the actual project pattern — const meta + export default meta + moduleMetadata:
// libs/<lib>/src/lib/my-component/my-component.stories.ts
import type { Meta, StoryObj } from '@storybook/angular';
import { moduleMetadata } from '@storybook/angular';
import { StoMyComponent } from './my-component.component';
const meta: Meta<StoMyComponent> = {
title: '<Lib>/MyComponent',
component: StoMyComponent,
decorators: [
moduleMetadata({
imports: [StoMyComponent],
}),
],
argTypes: {
data: { control: 'object', description: 'The data to display' },
},
args: {
data: {
/* default mock data */
},
},
};
export default meta;
type StoryType = StoryObj<StoMyComponent>;
export const Default: StoryType = {
render: (args) => ({
props: args,
template: `<sto-my-component [data]="data" />`,
}),
};
5. Export from Library
Add the component to the library's public API:
// libs/<lib>/src/index.ts
export * from './lib/my-component/my-component.component';
6. Write Tests
describe('StoMyComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [StoMyComponent],
}).compileComponents();
});
it('should create', () => {
const fixture = TestBed.createComponent(StoMyComponent);
expect(fixture.componentInstance).toBeTruthy();
});
});