Skip to content
Web Components Library - HaloLight

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 โ€‹

TechnologyVersionDescription
Stencil4.22.xWeb Components compiler
TypeScript5.xType system
Tailwind CSS4.0Utility-first CSS (build time)
Jest29.xUnit testing
Puppeteer23.xE2E 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 โ€‹

ComponentTagDescription
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.json

Quick Start โ€‹

Installation โ€‹

bash
npm install @halolight/ui
# or
pnpm add @halolight/ui

Define 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 โ€‹

PropertyTypeDefaultDescription
variant'primary' | 'secondary' | 'outline' | 'ghost''primary'Button variant
size'sm' | 'md' | 'lg''md'Button size
disabledbooleanfalseDisabled state
loadingbooleanfalseLoading state

Events: hlClick

hl-input โ€‹

PropertyTypeDefaultDescription
type'text' | 'password' | 'email' | 'number''text'Input type
placeholderstring''Placeholder text
disabledbooleanfalseDisabled state
errorstring''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 generate

Creating New Components โ€‹

  1. Use Stencil CLI to generate skeleton:
bash
npm run generate
# Enter component name (without hl- prefix)
  1. 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.