Web Components Library โ
HaloLight UI is a cross-framework Web Components library built with Stencil, featuring built-in Tailwind themes and OKLch color system.
GitHub: https://github.com/halolight/halolight-ui
npm: @halolight/ui
Tech Stack โ
| Technology | Version | Description |
|---|---|---|
| Stencil | 4.22.x | Web Components compiler |
| TypeScript | 5.x | Type system |
| Tailwind CSS | 4.0 | Utility-first CSS (build time) |
| Jest | 29.x | Unit testing |
| Puppeteer | 23.x | E2E testing |
Core Features โ
- Cross-framework Compatible: Based on Web Components standard, works with React, Vue, Angular, Svelte, and any framework
- OKLch Color Space: Uses perceptually uniform OKLch color space for theming
- Shadow DOM Encapsulation: Complete style isolation, avoiding conflicts
- TypeScript: Full type definition support
- Accessibility: WCAG 2.1 AA compliant
- Lightweight: On-demand loading, tree-shakeable
Component List โ
| Component | Tag | Description |
|---|---|---|
| Button | <hl-button> | Button with multiple variants and sizes |
| Input | <hl-input> | Input with validation and error states |
| Select | <hl-select> | Dropdown selector |
| Modal | <hl-modal> | Modal dialog |
| Card | <hl-card> | Card container |
| Table | <hl-table> | Data table with sorting and selection |
| Form | <hl-form> | Form container with validation |
Directory Structure โ
halolight-ui/
โโโ src/
โ โโโ components/ # Component source
โ โ โโโ hl-button/ # Button component
โ โ โ โโโ hl-button.tsx # Component logic
โ โ โ โโโ hl-button.css # Component styles
โ โ โ โโโ readme.md # Component docs
โ โ โ โโโ test/ # Component tests
โ โ โโโ hl-input/ # Input
โ โ โโโ hl-select/ # Select
โ โ โโโ hl-modal/ # Modal
โ โ โโโ hl-table/ # Table
โ โ โโโ hl-card/ # Card
โ โ โโโ hl-form/ # Form
โ โโโ global/ # Global styles
โ โ โโโ global.css # OKLch theme variables
โ โโโ utils/ # Utilities
โ โโโ themes/ # Theme configuration
โ โโโ components.d.ts # Auto-generated type definitions
โ โโโ index.ts # Export entry
โโโ dist/ # Build output
โโโ loader/ # Runtime loader
โโโ www/ # Development preview site
โโโ stencil.config.ts # Stencil configuration
โโโ tailwind.config.js # Tailwind configuration
โโโ tsconfig.json
โโโ package.jsonQuick Start โ
Installation โ
bash
npm install @halolight/ui
# or
pnpm add @halolight/uiDefine Custom Elements โ
Call once in any framework:
typescript
import { defineCustomElements } from '@halolight/ui/loader';
defineCustomElements();Vanilla JavaScript โ
html
<!DOCTYPE html>
<html>
<head>
<script type="module">
import { defineCustomElements } from 'https://unpkg.com/@halolight/ui/loader/index.js';
defineCustomElements();
</script>
</head>
<body>
<hl-button variant="primary">Click Me</hl-button>
</body>
</html>React โ
tsx
import { defineCustomElements } from '@halolight/ui/loader';
// Call once at app entry
defineCustomElements();
function App() {
return (
<div>
<hl-button variant="primary">Click Me</hl-button>
</div>
);
}TypeScript Support:
tsx
// vite-env.d.ts
/// <reference types="@halolight/ui/dist/types/components" />
import { JSX as HaloLightJSX } from '@halolight/ui/dist/types/components';
declare global {
namespace JSX {
interface IntrinsicElements extends HaloLightJSX.IntrinsicElements {}
}
}Vue 3 โ
vue
<template>
<hl-button variant="primary" @hl-click="handleClick">
Click Me
</hl-button>
</template>
<script setup lang="ts">
import { defineCustomElements } from '@halolight/ui/loader';
defineCustomElements();
const handleClick = () => {
console.log('Button clicked!');
};
</script>Angular โ
typescript
// app.module.ts
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { defineCustomElements } from '@halolight/ui/loader';
defineCustomElements();
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}html
<!-- app.component.html -->
<hl-button variant="primary" (hlClick)="handleClick()">
Click Me
</hl-button>Component API โ
hl-button โ
| Property | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'outline' | 'ghost' | 'primary' | Button variant |
size | 'sm' | 'md' | 'lg' | 'md' | Button size |
disabled | boolean | false | Disabled state |
loading | boolean | false | Loading state |
Events: hlClick
hl-input โ
| Property | Type | Default | Description |
|---|---|---|---|
type | 'text' | 'password' | 'email' | 'number' | 'text' | Input type |
placeholder | string | '' | Placeholder text |
disabled | boolean | false | Disabled state |
error | string | '' | Error message |
Events: hlChange, hlInput, hlFocus, hlBlur
Theme Customization โ
Dark Mode โ
Add dark class to parent element to enable dark theme:
html
<div class="dark">
<hl-button variant="primary">Dark Mode Button</hl-button>
</div>javascript
// Dynamic toggle
document.body.classList.toggle('dark');CSS Variable Override โ
Define theme variables using OKLch color space:
css
:root {
/* Primary color - using OKLch */
--hl-color-primary: oklch(0.65 0.15 250);
--hl-color-primary-hover: oklch(0.55 0.18 250);
--hl-color-primary-light: oklch(0.75 0.12 250);
/* Semantic colors */
--hl-color-success: oklch(0.7 0.18 145);
--hl-color-danger: oklch(0.63 0.26 25);
--hl-color-warning: oklch(0.78 0.16 75);
--hl-color-info: oklch(0.73 0.15 195);
/* Neutral colors */
--hl-bg-base: oklch(1 0 0);
--hl-text-primary: oklch(0.2 0 0);
--hl-border-color: oklch(0.9 0 0);
/* Border radius and spacing */
--hl-border-radius: 0.5rem;
--hl-spacing-md: 1rem;
}
/* Dark mode */
.dark {
--hl-color-primary: oklch(0.7 0.15 250);
--hl-bg-base: oklch(0.15 0 0);
--hl-text-primary: oklch(0.98 0 0);
}OKLch Color Space โ
OKLch is a perceptually uniform color space:
- L (Lightness): 0 (black) ~ 1 (white)
- C (Chroma): 0 (gray) ~ 0.4 (vivid)
- H (Hue): 0ยฐ ~ 360ยฐ (hue wheel)
css
/* oklch(lightness chroma hue / alpha) */
oklch(0.65 0.15 250) /* Blue */
oklch(0.7 0.18 145) /* Green */
oklch(0.63 0.26 25 / 0.8) /* Semi-transparent red */Development Guide โ
Common Commands โ
bash
# Install dependencies
npm install
# Start development server
npm start
# Production build
npm run build
# Run tests
npm test
# Generate new component
npm run generateCreating New Components โ
- Use Stencil CLI to generate skeleton:
bash
npm run generate
# Enter component name (without hl- prefix)- Implement component logic:
tsx
import { Component, Prop, Event, EventEmitter, h, Host } from '@stencil/core';
@Component({
tag: 'hl-example',
styleUrl: 'hl-example.css',
shadow: true,
})
export class HlExample {
@Prop() size: 'sm' | 'md' | 'lg' = 'md';
@Event() hlChange: EventEmitter<string>;
render() {
return (
<Host>
<div class={`hl-example hl-example--${this.size}`}>
<slot></slot>
</div>
</Host>
);
}
}Naming Conventions โ
- Component tags:
hl-{component-name} - CSS classes: BEM style
.hl-button--primary - Event names:
hl{EventName}(camelCase)
Browser Compatibility โ
OKLch color space support:
- Chrome 111+
- Safari 15.4+
- Firefox 113+
For older browsers, use PostCSS plugins for fallback conversion.
Related Projects โ
- halolight - Next.js reference implementation
- halolight-vue - Vue reference implementation
- halolight-angular - Angular implementation