@atomng/ui
v1.0.0
Published
Angular 19 component library — Atomic Design system built with Standalone Components, Angular Signals and SCSS design tokens.
Maintainers
Readme
@atomng/ui
Angular 19 component library — Atomic Design system built with Standalone Components, Angular Signals and SCSS design tokens.
What is @atomng/ui?
@atomng/ui is a fully Angular-native UI component library following the Atomic Design methodology (Atoms → Molecules → Organisms). Built entirely with:
- Standalone Components — no
NgModule, tree-shakable by default - Angular Signals — reactive state with
signal(),model(),computed() - SCSS design tokens — all values exposed as CSS custom properties
- ChangeDetectionStrategy.OnPush — every component is performance-optimised
- Dark mode — toggle via
data-theme="dark"on any parent element - Theming — runtime primary color switching with 18 built-in palettes
Installation
npm install @atomng/uiInstall required peer dependencies if not already present:
npm install @angular/core @angular/common @angular/animations rxjs lucide-angularSetup
1 — Import design tokens in your global styles.scss
/* All tokens at once */
@use 'node_modules/@atomng/ui/tokens/index' as *;
/* Or individually */
@use 'node_modules/@atomng/ui/tokens/colors' as *;
@use 'node_modules/@atomng/ui/tokens/typography' as *;
@use 'node_modules/@atomng/ui/tokens/spacing' as *;You can also configure stylePreprocessorOptions in angular.json to avoid the long path:
{
"stylePreprocessorOptions": {
"includePaths": ["node_modules/@atomng/ui/tokens"]
}
}Then simply:
@use 'colors' as *;
@use 'typography' as *;
@use 'spacing' as *;2 — Setup icons (required by Sidebar)
@atomng/ui uses lucide-angular for all icons. To use icons in your own components, import LucideAngularModule.pick() with only the icons you need:
import { LucideAngularModule, House, Settings } from 'lucide-angular';
@Component({
standalone: true,
// LucideAngularModule.pick() returns ModuleWithProviders — supported at runtime
// in Angular 14+ standalone components; cast `as any` bypasses the TS type check.
imports: [LucideAngularModule.pick({ House, Settings }) as any],
template: `<lucide-icon name="house" [size]="20" />`,
})
export class MyComponent {}Rule: always use
<lucide-icon>— never inline SVG.
3 — Add animations (required by Sidebar)
// app.config.ts
import { provideAnimations } from '@angular/platform-browser/animations';
export const appConfig: ApplicationConfig = {
providers: [
provideAnimations(),
],
};4 — Optional: configure the theme at bootstrap
// app.config.ts
import { provideSharedUiTheme } from '@atomng/ui/tokens';
export const appConfig: ApplicationConfig = {
providers: [
provideAnimations(),
provideSharedUiTheme({ primaryColor: 'indigo', mode: 'light' }),
],
};Usage
All components are standalone — import only what you need:
import { ButtonComponent } from '@atomng/ui/atoms';
import { InputComponent } from '@atomng/ui/molecules';
import { SidebarComponent } from '@atomng/ui/organisms';
import { ThemeToggleComponent } from '@atomng/ui/tokens';
// Or import everything from the root barrel:
import { ButtonComponent, InputComponent } from '@atomng/ui';<ui-button variant="solid" color="primary" [loading]="isLoading">
Enregistrer
</ui-button>
<ui-input placeholder="Rechercher…" />
<ui-badge color="success" variant="soft">Actif</ui-badge>
<!-- Light / System / Dark mode toggle -->
<ui-theme-toggle />
<!-- Primary color picker (18 palettes) -->
<ui-theme-picker (change)="onColorChange()" />Entry points
| Import path | Contents |
|---|---|
| @atomng/ui | Tout (atoms + molecules + organisms) |
| @atomng/ui/atoms | Button, Badge, Avatar, Checkbox, Chip, Progress, Skeleton, Slider, Switch, Tooltip, Link, Separator, Kbd |
| @atomng/ui/molecules | Input, Select, SelectSearch, Textarea, Alert, FormField, Tabs, Breadcrumb, Pagination, AvatarGroup, ButtonGroup, Toast |
| @atomng/ui/organisms | Sidebar, Card, Table, Modal, Accordion, DropdownMenu, NavigationMenu |
| @atomng/ui/tokens | ThemeService, ThemeToggleComponent, ThemePickerComponent, provideSharedUiTheme, color presets |
Components
Atoms
| Composant | Sélecteur | Inputs principaux |
|---|---|---|
| ButtonComponent | ui-button | variant (solid|outline|soft|subtle|ghost|link), color, size, loading, disabled, square |
| BadgeComponent | ui-badge | label, color, variant, size |
| AvatarComponent | ui-avatar | src, alt, initials, size (xs→3xl) |
| CheckboxComponent | ui-checkbox | label, size, color, checked (model), indeterminate |
| ChipComponent | ui-chip | label, color, size, closable |
| ProgressComponent | ui-progress | value, max, color, size |
| SkeletonComponent | ui-skeleton | width, height, rounded |
| SliderComponent | ui-slider | min, max, step, value (model) |
| SwitchComponent | ui-switch | label, size, color, checked (model) |
| TooltipComponent | ui-tooltip | content, placement |
| LinkComponent | ui-link | href, to (routerLink), external |
| SeparatorComponent | ui-separator | orientation, label |
| KbdComponent | ui-kbd | value |
Molecules
| Composant | Sélecteur | Inputs principaux |
|---|---|---|
| InputComponent | ui-input | type, placeholder, size, variant, color, disabled — CVA ✓ |
| SelectComponent | ui-select | options, placeholder, size, disabled — CVA ✓ |
| SelectSearchComponent | ui-select-search | options, placeholder, searchable — CVA ✓ |
| TextareaComponent | ui-textarea | placeholder, rows, size, variant — CVA ✓ |
| AlertComponent | ui-alert | color, title, description, closable — Output: close |
| FormFieldComponent | ui-form-field | label, name, errorMessage, required, size |
| TabsComponent | ui-tabs | tabs, activeIndex (model) |
| BreadcrumbComponent | ui-breadcrumb | items |
| PaginationComponent | ui-pagination | total, pageSize, page (model) |
| AvatarGroupComponent | ui-avatar-group | items, max, size |
| ButtonGroupComponent | ui-button-group | orientation |
| ToastComponent | ui-toast | message, color, duration |
Organisms
| Composant | Sélecteur | Inputs principaux |
|---|---|---|
| SidebarComponent | ui-sidebar | navGroups, footerGroups, user, collapsible, collapsed (model), showSearch |
| CardComponent | ui-card | title, description, padding |
| TableComponent | ui-table | columns, data, loading + UiTableCellDirective |
| ModalComponent | ui-modal | open (model), title, size |
| AccordionComponent | ui-accordion | items, multiple |
| DropdownMenuComponent | ui-dropdown-menu | items, trigger |
| NavigationMenuComponent | ui-navigation-menu | items, orientation |
Custom cell templates (UiTableCellDirective)
Use ng-template[uiCell] inside <ui-table> to render custom content per column:
import { TableComponent, UiTableCellDirective } from '@atomng/ui/organisms';
import { BadgeComponent } from '@atomng/ui/atoms';
@Component({
standalone: true,
imports: [TableComponent, UiTableCellDirective, BadgeComponent],
})<ui-table [columns]="cols" [data]="rows">
<ng-template uiCell="status" let-row>
<ui-badge [color]="row['statusColor']" variant="soft">
{{ row['status'] }}
</ui-badge>
</ng-template>
</ui-table>Theming
Primary color
@atomng/ui ships 18 color presets (Tailwind CSS v3 palettes, scale 50→950):
| Preset | Swatch 500 | Preset | Swatch 500 |
|---|---|---|---|
| green |
#22c55e | lime |
#84cc16 |
| emerald |
#10b981 | amber |
#f59e0b |
| teal |
#14b8a6 | orange |
#f97316 |
| cyan |
#06b6d4 | red |
#ef4444 |
| sky |
#0ea5e9 | rose |
#f43f5e |
| blue |
#3b82f6 | pink |
#ec4899 |
| indigo |
#6366f1 | fuchsia |
#d946ef |
| violet |
#8b5cf6 | purple |
#a855f7 |
| slate |
#64748b | zinc |
#71717a |
Each preset overrides the CSS custom properties --color-primary-50 → --color-primary-950 on :root.
Set the color at bootstrap via provideSharedUiTheme(), or at runtime:
import { ThemeService } from '@atomng/ui/tokens';
export class MyComponent {
private theme = inject(ThemeService);
changeColor(): void {
// Use a preset name
this.theme.setPrimary('violet');
// Or pass a full custom palette (11 shades, 50→950)
this.theme.setPrimary({
50: '#fdf4ff', 100: '#fae8ff', 200: '#f5d0fe', 300: '#f0abfc',
400: '#e879f9', 500: '#d946ef', 600: '#c026d3', 700: '#a21caf',
800: '#86198f', 900: '#701a75', 950: '#4a044e',
});
}
}ThemeService API
theme = inject(ThemeService);
// Signals (read-only)
theme.activePreset() // PrimaryColorPreset | null
theme.activeMode() // 'light' | 'dark' | 'system'
theme.isDark() // boolean — resolved, accounts for 'system'
theme.presets // ColorPresetMeta[] — all 18 presets for a picker UIDark / Light / System mode
this.theme.setMode('dark'); // force dark
this.theme.setMode('light'); // force light
this.theme.setMode('system'); // follow OS preference
this.theme.toggleMode(); // light ↔ darkThe mode and selected color are automatically persisted to localStorage and restored on the next page load.
Add the built-in components anywhere in your app:
<!-- Toggle light / dark -->
<ui-theme-toggle />
<!-- Visual color picker (all 18 presets) -->
<ui-theme-picker />Dark mode in your own SCSS
Dark mode is activated by data-theme="dark" on the <html> element (set automatically by ThemeService). All CSS custom properties cascade down:
.my-card {
background: var(--color-bg); // white in light, #030712 in dark
color: var(--color-text); // #111827 in light, #f9fafb in dark
border: 1px solid var(--color-border);
}Design tokens reference
// ── Backgrounds
var(--color-bg) // Page background
var(--color-bg-subtle) // Subtle surface (cards, inputs)
var(--color-bg-muted) // Muted surface
// ── Text
var(--color-text) // Primary text
var(--color-text-muted) // Secondary text
var(--color-text-subtle) // Tertiary / placeholder
// ── Borders
var(--color-border)
var(--color-border-muted)
// ── Brand
var(--color-primary-500) // Active primary color (runtime)
var(--color-primary-100) // … through 950
// ── Typography
var(--font-sans) // Primary font (system-ui)
var(--font-mono) // Monospace
var(--text-xs) // 11px
var(--text-sm) // 13px
var(--text-base) // 15px
var(--text-lg) // 18px
var(--text-xl) // 20px
var(--text-2xl) // 24px
var(--font-medium) // 500
var(--font-semibold) // 600
var(--font-bold) // 700
// ── Spacing (base 4px)
var(--spacing-1) // 4px
var(--spacing-2) // 8px
var(--spacing-4) // 16px
var(--spacing-6) // 24px
var(--spacing-8) // 32px
var(--spacing-12) // 48px
// ── Radius
var(--radius-sm) // 4px
var(--radius-md) // 6px
var(--radius-lg) // 10px
var(--radius-xl) // 14px
// ── Transitions
var(--transition-colors)
var(--transition-fast)
var(--transition-slow)Requirements
| Dependency | Version | Notes |
|---|---|---|
| @angular/core | >= 19.0.0 | |
| @angular/common | >= 19.0.0 | |
| @angular/animations | >= 19.0.0 | Required by Sidebar |
| @angular/forms | >= 19.0.0 | Required by CVA components (Input, Select…) |
| @angular/router | >= 19.0.0 | Required by Sidebar, Link, Breadcrumb |
| rxjs | >= 7.4.0 | |
| lucide-angular | >= 1.0.0 | Required by Sidebar (icons) |
License
MIT © LIBASSE MBAYE
