Skip to main content

Creating a Component

This guide covers the end-to-end process for adding a new publishable component to Synapse UI.

Prerequisites

Step 1: Generate the Library

nx g @nx/angular:library my-component \
--directory=libs/ui \
--publishable \
--importPath=@synapse-ui/my-component \
--standalone \
--tags=scope:ui,type:lib

This creates:

libs/ui/my-component/
├── src/
│ ├── index.ts
│ └── lib/
├── ng-package.json
├── project.json
└── README.md

Step 2: Implement the Component

Follow the component strategy conventions:

// my-component.component.ts
import { ChangeDetectionStrategy, Component, input, output } from '@angular/core';

@Component({
selector: 'synapse-my-component',
standalone: true,
templateUrl: './my-component.component.html',
styleUrl: './my-component.component.css',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MyComponentComponent {
readonly label = input<string>('');
readonly clicked = output<void>();
}

Checklist

  • Selector prefixed with synapse-
  • ChangeDetectionStrategy.OnPush
  • Signal-based input() and output()
  • Styles use --synapse-* tokens only
  • Public API exported from src/index.ts

Step 3: Add Storybook Stories

// my-component.stories.ts
import type { Meta, StoryObj } from '@storybook/angular';
import { MyComponentComponent } from './my-component.component';

const meta: Meta<MyComponentComponent> = {
title: 'UI/MyComponent',
component: MyComponentComponent,
tags: ['autodocs'],
};

export default meta;
type Story = StoryObj<MyComponentComponent>;

export const Default: Story = {
args: { label: 'Hello' },
};

Required stories: Default, Disabled (if applicable), Theme variants.

Step 4: Write Tests

// my-component.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyComponentComponent } from './my-component.component';

describe('MyComponentComponent', () => {
let fixture: ComponentFixture<MyComponentComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [MyComponentComponent],
}).compileComponents();

fixture = TestBed.createComponent(MyComponentComponent);
fixture.detectChanges();
});

it('should create', () => {
expect(fixture.componentInstance).toBeTruthy();
});
});

Step 5: Document the Component

  1. Create docs/components/my-component.md following the existing template.
  2. Add a link in docs/README.md if it's a public component.
  3. Update the component catalog table in README.md.

Step 6: Verify Build

nx lint my-component
nx test my-component
nx build my-component

Step 7: Integrate in Sandbox

Add the component to apps/sandbox to validate real-world usage:

import { MyComponentComponent } from '@synapse-ui/my-component';

Module Boundary Rules

Your componentCan import
libs/ui/*@synapse-ui/theme, @synapse-ui/core
libs/ui/*Other @synapse-ui/* UI libs (avoid circular deps)
libs/core@synapse-ui/theme only
libs/themeNothing from UI or core

Enforced via @nx/enforce-module-boundaries ESLint rule.