Neo-Minimal design system for Angular applications.
Luma is a design system built on Neo-Minimalism - a design philosophy that creates interfaces with calm, intentional simplicity. It provides 24 semantic design tokens and Angular components that prioritize:
- Visual Silence - Elements don't compete; hierarchy is perceived effortlessly
- Functional Whitespace - Space as invisible structure, not empty filler
- Calm Interactions - Gentle feedback with natural transitions
- Silent Accessibility - WCAG AA compliance built into the design, not bolted on
- 24 semantic design tokens - Simple, runtime-customizable theme system
- Standard Tailwind utilities - Familiar syntax (
bg-primary,text-foreground,rounded-md) - Angular 19+ standalone components - Modern reactive patterns with signals
- Type-safe variants - CVA-powered variant system with TypeScript safety
- OKLCH color space - Perceptually uniform colors with predictable lightness
- Automatic dark theme - Toggle with a single class (
<html class="dark">) - WCAG AA accessible - Focus management, ARIA attributes, keyboard navigation
| Package | Description |
|---|---|
@lumaui/tokens |
24 semantic design tokens (light + dark) |
@lumaui/angular |
Angular components and directives |
@lumaui/core |
Framework-agnostic CVA variant definitions |
npm install @lumaui/angular @lumaui/tokens tailwindcss@next @tailwindcss/postcss@next// postcss.config.mjs
export default {
plugins: {
'@tailwindcss/postcss': {},
},
};/* src/styles.css */
/* Luma design tokens (includes Tailwind, tokens, and component classes) */
@import '@lumaui/tokens/build/luma.css';
/* Optional: Dark theme */
@import '@lumaui/tokens/build/luma-dark.css';That's it! No additional configuration needed. The luma.css file includes everything:
- ✅ Tailwind CSS v4 base
- ✅ 45 design tokens
- ✅ Component class manifest
- ✅ Automatic class discovery
import { LmButtonDirective } from '@lumaui/angular';
@Component({
selector: 'app-root',
imports: [LmButtonDirective],
template: `<button lumaButton lmVariant="primary">Click me</button>`,
})
export class AppComponent {}See it in action:
ng serveOpen http://localhost:4200 - you should see a styled purple button! 🎉
Dark theme toggle:
<!-- Toggle dark theme by adding 'dark' class to <html> -->
<html class="dark">
<!-- Your app uses dark theme tokens automatically -->
</html>import { Component } from '@angular/core';
import { LmButtonDirective } from '@lumaui/angular';
@Component({
selector: 'app-example',
imports: [LmButtonDirective],
template: `
<button lumaButton lmVariant="primary" lmSize="md">Click me</button>
`,
})
export class ExampleComponent {}Directive-based button with semantic color variants.
<!-- Variants: primary, secondary, outline, ghost, destructive -->
<button lumaButton lmVariant="primary">Primary Action</button>
<button lumaButton lmVariant="secondary">Secondary</button>
<button lumaButton lmVariant="outline">Outline</button>
<button lumaButton lmVariant="ghost">Ghost</button>
<button lumaButton lmVariant="destructive">Delete</button>
<!-- Sizes: sm, md, lg -->
<button lumaButton lmSize="sm">Small</button>
<button lumaButton lmSize="md">Medium</button>
<button lumaButton lmSize="lg">Large</button>
<!-- States -->
<button lumaButton [lmDisabled]="true">Disabled</button>Inline status indicators with semantic variants.
<span lumaBadge lmVariant="default">Default</span>
<span lumaBadge lmVariant="secondary">Secondary</span>
<span lumaBadge lmVariant="destructive">Error</span>
<span lumaBadge lmVariant="success">Success</span>
<span lumaBadge lmVariant="warning">Warning</span>
<span lumaBadge lmVariant="outline">Outline</span>Compositional card with header, title, description, and content directives.
<luma-card lmVariant="default">
<div lumaCardHeader>
<h3 lumaCardTitle lmSize="large">Card Title</h3>
<p lumaCardDescription lmSize="default">
Brief description of card content
</p>
</div>
<div lumaCardContent>
<p>Main card content goes here.</p>
</div>
<div lumaCardFooter>
<button lumaButton lmVariant="primary">Action</button>
</div>
</luma-card>Contextual information overlay.
<button lumaButton lumaTooltip="Click to save changes" lmPosition="top">
Save
</button>Dialog overlay for focused interactions.
<luma-modal [(lmOpen)]="isOpen" lmSize="md">
<div lumaModalHeader>
<h2 lumaModalTitle>Modal Title</h2>
</div>
<div lumaModalContent>
<p>Modal content</p>
</div>
<div lumaModalFooter>
<button lumaButton (click)="isOpen = false">Close</button>
</div>
</luma-modal>Tab navigation with underline and pills variants.
<luma-tabs [lmDefaultValue]="'tab-1'" lmVariant="underline">
<div lumaTabsList>
<button lumaTabsTrigger="tab-1">Tab 1</button>
<button lumaTabsTrigger="tab-2">Tab 2</button>
</div>
<div lumaTabsPanel="tab-1">Content 1</div>
<div lumaTabsPanel="tab-2">Content 2</div>
</luma-tabs>Expandable content sections.
<luma-accordion-item [lmOpen]="true" lmVariant="default">
<div lumaAccordionTrigger>
<span lumaAccordionTitle>Section Title</span>
<span lumaAccordionIcon>▼</span>
</div>
<div lumaAccordionContent>
<p>Expandable content</p>
</div>
</luma-accordion-item>Service-based notifications.
import { inject } from '@angular/core';
import { LmToastService } from '@lumaui/angular';
export class MyComponent {
toast = inject(LmToastService);
showSuccess() {
this.toast.show('Operation successful!', 'success');
}
}Luma uses 24 semantic design tokens for consistent, runtime-customizable theming.
| Token | Purpose |
|---|---|
--color-primary |
Primary actions (buttons, links) |
--color-primary-foreground |
Text on primary backgrounds |
--color-secondary |
Secondary actions, subtle backgrounds |
--color-destructive |
Destructive actions, errors |
--color-muted |
Disabled states, subtle elements |
--color-background |
App background |
--color-foreground |
Primary text color |
--color-border |
Borders, dividers |
See all 24 tokens in CLAUDE.md
Change colors globally (affects all components):
:root {
--color-primary: oklch(0.6 0.15 180); /* Cyan brand */
--color-primary-foreground: oklch(1 0 0); /* White text */
}Customize dark theme colors:
html.dark {
--color-primary: oklch(0.75 0.12 180); /* Brighter cyan for dark mode */
--color-background: oklch(0.15 0.005 290); /* Darker background */
}Override specific component instances using Tailwind utilities:
<button lumaButton class="bg-accent hover:bg-accent/80">Custom Color</button>Create themed sections:
<div class="theme-error">
<!-- All buttons in this section use error colors -->
<button lumaButton>Delete</button>
</div>.theme-error {
--color-primary: var(--color-destructive);
--color-primary-foreground: var(--color-destructive-foreground);
}export class ThemeService {
toggleDarkMode() {
document.documentElement.classList.toggle('dark');
}
setCustomTheme(primaryColor: string) {
document.documentElement.style.setProperty('--color-primary', primaryColor);
}
}# Start the docs/playground app
npm run dev
# Build all packages
npm run build
# Run component tests
npm run test:components
# Lint all projects
npm run lint:all
# Format code
npm run format- CLAUDE.md - Comprehensive development guide, Neo-Minimal design principles, token architecture, and contribution standards
- Component Docs - Each component has detailed documentation in
packages/angular/src/lib/*/- Usage examples
- Semantic token references
- Accessibility features
- Customization patterns
Luma follows strict Neo-Minimal design principles. Before contributing:
- Read CLAUDE.md for design philosophy and technical guidelines
- Ensure components use only the 24 semantic tokens (no component-specific tokens)
- Follow accessibility standards (WCAG AA minimum)
- Write comprehensive tests including token consumption and override tests
MIT