@lumston/ds-angular
v0.1.3
Published
Lumston Design System for Angular applications
Readme
@lumston/ds-angular
Angular component library for the Lumston Design System.
Requirements
- Angular 17 or later
@angular/common,@angular/core,@angular/platform-browser
Installation
npm install @lumston/ds-angularDefault font
The library uses Nunito as its default font family via the --ls-font-family token. Nunito is not bundled — you must load it yourself.
Option 1 — Google Fonts (recommended):
Add the following <link> tags inside <head> in your index.html:
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap"
rel="stylesheet"
/>Option 2 — Self-hosted:
Download the font files and add a @font-face declaration in your global stylesheet before the library import:
@font-face {
font-family: 'Nunito';
src: url('/assets/fonts/Nunito-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@import '@lumston/ds-angular/styles';Override the font:
To use a different font, override the token after importing the library styles:
@import '@lumston/ds-angular/styles';
:root {
--ls-font-family: 'Inter', sans-serif;
}Dark theme
All components support dark mode out of the box. Dark styles activate when the dark class is present on <body>.
How it works
The library uses a CSS class strategy — no media query is required. Components listen for body.dark and switch their color tokens automatically:
/* Light mode — default */
.ls-header { background-color: var(--ls-header-bg, #ffffff); }
/* Dark mode — activated by body.dark */
body.dark .ls-header { background-color: var(--ls-header-bg-dark, #0e1726); }Enabling dark mode
Toggle the dark class on <body> from your Angular service:
// theme.service.ts
export class ThemeService {
setDark(enabled: boolean): void {
document.body.classList.toggle('dark', enabled);
}
}Supporting light, dark, and system preferences
// theme.service.ts
import { Injectable } from '@angular/core';
type Theme = 'light' | 'dark' | 'system';
@Injectable({ providedIn: 'root' })
export class ThemeService {
apply(theme: Theme): void {
if (theme === 'dark') {
document.body.classList.add('dark');
} else if (theme === 'light') {
document.body.classList.remove('dark');
} else {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
document.body.classList.toggle('dark', prefersDark);
}
}
watchSystem(): void {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
document.body.classList.toggle('dark', e.matches);
});
}
}Persisting the user preference
// On app initialization
const saved = localStorage.getItem('theme') as Theme | null;
this.themeService.apply(saved ?? 'system');Overriding dark mode tokens
All dark variants are CSS custom properties. Override them after the library import:
@import '@lumston/ds-angular/styles';
body.dark {
--ls-header-bg-dark: #1a1a2e;
--ls-sidebar-bg-dark: #16213e;
--ls-color-primary: #818cf8;
}Components with dark mode support
| Component | Dark tokens |
|---|---|
| Header | --ls-header-bg-dark, --ls-header-shadow-dark |
| Sidebar | --ls-sidebar-bg-dark, --ls-sidebar-header-bg-dark, --ls-sidebar-icon-color-dark, --ls-sidebar-sublink-indicator-color-dark |
| Table | --ls-table-border-color, --ls-table-header-bg, --ls-table-header-color, --ls-table-cell-color, --ls-table-stripe-bg, --ls-table-hover-bg |
| Stepper | --ls-stepper-connector-color, --ls-stepper-bg, --ls-stepper-text-color |
| Drag | --ls-drag-ghost-bg, --ls-drag-drop-indicator-color |
| Button (dark color) | --ls-color-dark-dm |
All dark token overrides must be placed inside a
body.dark { }block, after the library stylesheet import.
Peer dependencies by component
Some components require additional packages that are not bundled with the library.
PhoneInputComponent (ls-phone-input)
Requires flag-icons for country flag rendering.
npm install flag-iconsRegister the stylesheet once in your application, before the library styles:
Option 1 — global CSS file (styles.css):
@import 'flag-icons/css/flag-icons.min.css';
@import '@lumston/ds-angular/styles';Option 2 — angular.json under styles:
"styles": [
"node_modules/flag-icons/css/flag-icons.min.css",
"node_modules/@lumston/ds-angular/styles/index.css",
"src/styles.css"
]
flag-iconsmust be loaded before any component that uses flag sprites, so place it above the library stylesheet.
Importing styles
Add the library stylesheet once in your application's global CSS file (e.g. styles.css):
@import '@lumston/ds-angular/styles';Or in angular.json under styles:
"styles": [
"node_modules/@lumston/ds-angular/styles/index.css",
"src/styles.css"
]The stylesheet includes all design tokens (CSS custom properties), base reset rules, and component styles. It must be loaded before your application styles so that overrides work correctly.
Using components
All components are standalone. Import them directly in your Angular component or module:
import { ButtonComponent } from '@lumston/ds-angular';
@Component({
standalone: true,
imports: [ButtonComponent],
template: `<ls-button variant="filled">Save</ls-button>`,
})
export class MyComponent {}Overriding design tokens
The library exposes its entire palette and configuration as CSS custom properties on :root. You can override any token by redefining it after the library import in your global stylesheet.
Override globally
/* styles.css */
@import '@lumston/ds-angular/styles';
:root {
/* Brand colors */
--ls-color-primary: #ff6b35;
--ls-color-primary-light: #fff0eb;
--ls-color-primary-dark-light: rgba(255, 107, 53, 0.15);
/* Typography */
--ls-font-family: 'Inter', sans-serif;
/* Border radius */
--ls-border-radius-md: 0.25rem;
--ls-border-radius-lg: 0.5rem;
--ls-border-radius-full: 9999px;
}Override per theme (scoped)
You can scope overrides to a CSS class to support multiple themes simultaneously:
.theme-corporate {
--ls-color-primary: #1a3c6e;
--ls-color-primary-light: #e8eef7;
--ls-color-primary-dark-light: rgba(26, 60, 110, 0.15);
}
.theme-dark {
--ls-color-primary: #818cf8;
--ls-color-primary-light: #1e1b4b;
--ls-color-primary-dark-light: rgba(129, 140, 248, 0.15);
}Apply the class to a wrapper element in your template:
<div class="theme-corporate">
<ls-button variant="filled">Submit</ls-button>
</div>Available tokens
Colors
| Token | Default | Description |
|---|---|---|
| --ls-color-primary | #4361ee | Primary brand color |
| --ls-color-primary-light | #eaf1ff | Primary tint background |
| --ls-color-primary-dark-light | rgba(67,97,238,.15) | Primary overlay |
| --ls-color-secondary | #805dca | Secondary brand color |
| --ls-color-secondary-light | #ebe4f7 | Secondary tint background |
| --ls-color-secondary-dark-light | rgba(128,93,202,.15) | Secondary overlay |
| --ls-color-success | #00ab55 | Success state |
| --ls-color-success-light | #ddf5f0 | Success tint background |
| --ls-color-success-dark-light | rgba(0,171,85,.15) | Success overlay |
| --ls-color-danger | #e7515a | Danger / destructive state |
| --ls-color-danger-light | #fff5f5 | Danger tint background |
| --ls-color-danger-dark-light | rgba(231,81,90,.15) | Danger overlay |
| --ls-color-error | #e7515a | Error state (alias of danger) |
| --ls-color-error-light | #fff5f5 | Error tint background |
| --ls-color-error-dark-light | rgba(231,81,90,.15) | Error overlay |
| --ls-color-warning | #e2a03f | Warning state |
| --ls-color-warning-light | #fff9ed | Warning tint background |
| --ls-color-warning-dark-light | rgba(226,160,63,.15) | Warning overlay |
| --ls-color-info | #2196f3 | Informational state |
| --ls-color-info-light | #e7f7ff | Info tint background |
| --ls-color-info-dark-light | rgba(33,150,243,.15) | Info overlay |
| --ls-color-dark | #3b3f5c | Dark neutral |
| --ls-color-dark-dm | #8892a4 | Dark neutral adapted for dark mode (higher contrast on dark backgrounds) |
| --ls-color-dark-light | #eaeaec | Dark tint background |
| --ls-color-dark-dark-light | rgba(59,63,92,.15) | Dark overlay |
| --ls-color-black | #0e1726 | Near-black |
| --ls-color-black-light | #e3e4eb | Near-black tint |
| --ls-color-black-dark-light | rgba(14,23,38,.15) | Near-black overlay |
| --ls-color-white | #ffffff | White |
| --ls-color-white-light | #e0e6ed | White variant |
| --ls-color-white-dark | #888ea8 | White muted |
| --ls-gradient-start | #ef1262 | Gradient start color |
| --ls-gradient-end | #4361ee | Gradient end color |
Typography
| Token | Default | Description |
|---|---|---|
| --ls-font-family | 'Nunito', sans-serif | Base font family |
Transitions
| Token | Default | Description |
|---|---|---|
| --ls-transition-duration | 300ms | Default transition duration |
| --ls-transition-accordion-duration | 400ms | Accordion expand/collapse duration |
Border radius
| Token | Default | Description |
|---|---|---|
| --ls-border-radius-md | 0.375rem | Medium border radius |
| --ls-border-radius-lg | 0.5rem | Large border radius |
| --ls-border-radius-full | 9999px | Pill / full border radius |
Inputs
| Token | Default | Description |
|---|---|---|
| --ls-color-input-border | #d0d2d6 | Input border color |
| --ls-color-input-label | #3b3f5c | Input label color |
| --ls-color-input-bg-filled | #f4f4f4 | Filled input background |
| --ls-color-helper-text | #888ea8 | Helper / hint text color |
| --ls-color-text-placeholder | #adb5bd | Placeholder text color |
Header
| Token | Default | Description |
|---|---|---|
| --ls-header-height | 56px | Minimum height of the header |
| --ls-header-z-index | 40 | Stack order of the header |
| --ls-header-padding-x | 1.25rem | Horizontal padding |
| --ls-header-bg | #ffffff | Background color (light mode) |
| --ls-header-bg-dark | #0e1726 | Background color (dark mode) |
| --ls-header-shadow | 0 1px 3px 0 rgba(0,0,0,.08) | Box shadow (light mode) |
| --ls-header-shadow-dark | 0 1px 3px 0 rgba(0,0,0,.3) | Box shadow (dark mode) |
| --ls-header-gap | 0.375rem | Gap between header end slot items |
Sidebar
| Token | Default | Description |
|---|---|---|
| --ls-sidebar-width | 260px | Sidebar width |
| --ls-sidebar-bg | #ffffff | Background color (light mode) |
| --ls-sidebar-bg-dark | #0e1726 | Background color (dark mode) |
| --ls-sidebar-z-index | 50 | Stack order of the sidebar |
| --ls-sidebar-item-color | #506690 | Nav item text color |
| --ls-sidebar-item-active-color | #4361ee | Active nav item text color |
| --ls-sidebar-item-active-bg | rgba(67,97,238,.12) | Active nav item background |
| --ls-sidebar-item-hover-color | #4361ee | Nav item text color on hover |
| --ls-sidebar-item-hover-bg | rgba(0,0,0,.05) | Nav item background on hover |
| --ls-sidebar-icon-color | #506690 | Icon color |
| --ls-sidebar-icon-color-dark | #506690 | Icon color (dark mode) |
| --ls-sidebar-header-bg | rgba(255,255,255,.3) | Section header background |
| --ls-sidebar-header-bg-dark | rgba(0,0,0,.08) | Section header background (dark mode) |
| --ls-sidebar-header-color | #888ea8 | Section header text color |
| --ls-sidebar-sublink-indicator-color | #bfc9d4 | Sub-item connector line color |
| --ls-sidebar-sublink-indicator-color-dark | #3b3f5c | Sub-item connector line color (dark mode) |
| --ls-sidebar-head-padding | 0.75rem 1rem | Sidebar head area padding |
| --ls-sidebar-head-height | 4rem | Sidebar head area height |
| --ls-sidebar-close-color | #506690 | Close button icon color |
| --ls-sidebar-close-hover-bg | rgba(0,0,0,.05) | Close button background on hover |
| --ls-sidebar-close-hover-color | #4361ee | Close button icon color on hover |
Modal
| Token | Default | Description |
|---|---|---|
| --ls-modal-z-index | 1000 | Modal z-index |
| --ls-modal-backdrop-bg | rgba(0,0,0,.5) | Modal backdrop color |
Drawer
| Token | Default | Description |
|---|---|---|
| --ls-drawer-z-index | 1200 | Drawer z-index |
| --ls-drawer-backdrop-bg | rgba(0,0,0,.5) | Drawer backdrop color |
| --ls-drawer-width | 320px | Drawer width (left/right) |
| --ls-drawer-height | 280px | Drawer height (top/bottom) |
Menu
| Token | Default | Description |
|---|---|---|
| --ls-menu-z-index | 1001 | Dropdown menu z-index |
Select
| Token | Default | Description |
|---|---|---|
| --ls-select-bg | #ffffff | Select panel background |
| --ls-select-border | #e0e6ed | Select panel border color |
| --ls-select-option-hover | #f1f2f3 | Option background on hover |
Tab
| Token | Default | Description |
|---|---|---|
| --ls-tab-border-color | var(--ls-color-white-light) | Tab underline / border color |
Table
| Token | Default | Description |
|---|---|---|
| --ls-table-border-color | rgba(224,230,237,.4) | Table border color |
| --ls-table-header-bg | #f6f8fa | Table header background |
| --ls-table-header-color | #3b3f5c | Table header text color |
| --ls-table-cell-color | #515365 | Table cell text color |
| --ls-table-stripe-bg | rgba(224,230,237,.2) | Striped row background |
| --ls-table-hover-bg | rgba(224,230,237,.2) | Row background on hover |
Date picker
| Token | Default | Description |
|---|---|---|
| --ls-color-dp-selected-bg | #4361ee | Selected date background |
| --ls-color-dp-range-bg | #eaf1ff | Date range highlight background |
| --ls-color-dp-cell-hover-bg | #f0f4ff | Date cell background on hover |
| --ls-color-dp-disabled-text | #888ea8 | Disabled date text color |
Stepper
| Token | Default | Description |
|---|---|---|
| --ls-stepper-connector-color | #e0e6ed | Connector line color |
| --ls-stepper-active-color | var(--ls-color-primary) | Active step indicator color |
| --ls-stepper-complete-color | var(--ls-color-primary) | Completed step indicator color |
| --ls-stepper-error-color | var(--ls-color-danger) | Error step indicator color |
| --ls-stepper-disabled-opacity | 0.5 | Opacity for disabled steps |
| --ls-stepper-bg | #ffffff | Step indicator background |
| --ls-stepper-text-color | #3b3f5c | Step label text color |
| --ls-stepper-icon-size | 2rem | Step indicator icon size |
| --ls-stepper-transition-duration | var(--ls-transition-duration) | Step transition duration |
Color picker
| Token | Default | Description |
|---|---|---|
| --ls-cp-gap | 8px | Gap between color swatches |
| --ls-cp-swatch-size | 28px | Swatch size (default) |
| --ls-cp-swatch-size-sm | 20px | Swatch size (small) |
Drag
| Token | Default | Description |
|---|---|---|
| --ls-drag-drop-indicator-color | var(--ls-color-primary) | Drop zone indicator color |
| --ls-drag-disabled-opacity | 0.5 | Opacity when drag is disabled |
| --ls-drag-item-dragging-opacity | 0.4 | Opacity of the item being dragged |
| --ls-drag-ghost-bg | #ffffff | Drag ghost element background |
Map
| Token | Default | Description |
|---|---|---|
| --ls-map-border-radius | var(--ls-border-radius-md) | Map container border radius |
| --ls-map-disabled-opacity | 0.6 | Map opacity when disabled |
