121
GitHub
Framework guide

Elements

Standards-based custom elements for the complete Lumen catalog, ready for plain HTML or any framework through the same shared class and data contract.

Surface
Native
API
DOM
Package
Elements

Installation

Install the Elements package, load its stylesheet once, register Lumen elements, and use lumen-* tags anywhere HTML is valid. Behavior-backed elements include overlays, context menus, select, forms, rich text, schedule, toast, DataTable, ThemeBuilder, and VirtualList.

pnpm

bash
pnpm add @santi020k/lumen-elements
pnpm add @santi020k/lumen-elements

npm

bash
npm install @santi020k/lumen-elements
npm install @santi020k/lumen-elements

yarn

bash
yarn add @santi020k/lumen-elements
yarn add @santi020k/lumen-elements

Usage Example

html
<script type="module">
  import { defineLumenElements } from '@santi020k/lumen-elements/define'

  defineLumenElements()
</script>

<lumen-card>
  <label for="email">Email</label>
  <lumen-input id="email" type="email" placeholder="you@example.com"></lumen-input>
  <lumen-button>Subscribe</lumen-button>
</lumen-card>
<script type="module">
  import { defineLumenElements } from '@santi020k/lumen-elements/define'

  defineLumenElements()
</script>

<lumen-card>
  <label for="email">Email</label>
  <lumen-input id="email" type="email" placeholder="you@example.com"></lumen-input>
  <lumen-button>Subscribe</lumen-button>
</lumen-card>

Overview

  • Custom elements expose the shared class and data contract through lumen-* tags that work in plain HTML or any framework.
  • Call defineLumenElements once before using the tags; behavior-backed elements include DataTable selection/sort, form validation, calendar grids, OTP segmentation, date range syncing, rich text commands, context menu triggers, schedule drag/drop, resizable pane sizing, ThemeBuilder export, VirtualList range events, overlays, select, tabs, tooltip, and toast.
  • Use lumen add Component --target elements or lumen add recipe-name --target elements when you want local Elements starter files.

API Reference

DOM APIs, registration, and progressive enhancement functions for Lumen elements.

defineLumenElements

Registers all 79 Lumen web components in the custom element registry. Call once before using any <lumen-*> tags. Optionally pass a custom registry for scoped usage.

Signature / AttributeDescription
registry
CustomElementRegistry (optional)
Custom element registry to register against. Defaults to the global customElements.

Example

html
<script type="module">
  import { defineLumenElements } from '@santi020k/lumen-elements/define'

  defineLumenElements()
</script>

<lumen-card>
  <lumen-button>Click me</lumen-button>
</lumen-card>
<script type="module">
  import { defineLumenElements } from '@santi020k/lumen-elements/define'

  defineLumenElements()
</script>

<lumen-card>
  <lumen-button>Click me</lumen-button>
</lumen-card>

enhanceLumenForms

Enhances forms marked with [data-ui-form] with native constraint validation, custom error messages via data-error-* attributes, and field description syncing. Works without registering custom elements.

Signature / AttributeDescription
root
ParentNode (optional)
Root element to search for [data-ui-form] forms. Defaults to document.
data-error-required
attribute
Custom message shown when a required field is empty.
data-error-type
attribute
Custom message shown when the value does not match the input type (e.g. email).
data-error-pattern
attribute
Custom message shown when the value does not match the pattern attribute.
data-error-min / data-error-max
attribute
Custom message for range violations.

Example

html
<script type="module">
  import { enhanceLumenForms } from '@santi020k/lumen-elements/define'

  enhanceLumenForms()
</script>

<form data-ui-form>
  <label for="email">Email</label>
  <input
    id="email"
    type="email"
    required
    data-error-required="Please enter your email"
    data-error-type="Enter a valid email address"
    class="ui-input"
  />
  <button type="submit" class="ui-button ui-button--default">Sign up</button>
</form>
<script type="module">
  import { enhanceLumenForms } from '@santi020k/lumen-elements/define'

  enhanceLumenForms()
</script>

<form data-ui-form>
  <label for="email">Email</label>
  <input
    id="email"
    type="email"
    required
    data-error-required="Please enter your email"
    data-error-type="Enter a valid email address"
    class="ui-input"
  />
  <button type="submit" class="ui-button ui-button--default">Sign up</button>
</form>

enhanceLumenCalendars

Enhances elements marked with [data-ui-calendar] or <lumen-calendar> with generated date grids, hidden input values, month navigation, selection, min/max clamping, and keyboard focus.

Signature / AttributeDescription
root
ParentNode (optional)
Root element to search for calendars. Defaults to document.
month
YYYY-MM
Visible month for generated calendars.
value
YYYY-MM-DD
Initial selected date copied to the hidden input.
min / max
YYYY-MM-DD
Inclusive selectable date bounds.
name
attribute
Forwarded to the generated hidden input for form submission.

Example

html
<script type="module">
  import { enhanceLumenCalendars } from '@santi020k/lumen-elements/define'

  enhanceLumenCalendars()
</script>

<lumen-calendar
  max="2026-07-31"
  min="2026-07-01"
  month="2026-07"
  name="delivery"
></lumen-calendar>
<script type="module">
  import { enhanceLumenCalendars } from '@santi020k/lumen-elements/define'

  enhanceLumenCalendars()
</script>

<lumen-calendar
  max="2026-07-31"
  min="2026-07-01"
  month="2026-07"
  name="delivery"
></lumen-calendar>

enhanceLumenDateRangePickers

Enhances elements marked with [data-ui-date-range-picker] so paired native date inputs keep min/max constraints in sync. Works without registering custom elements.

Signature / AttributeDescription
root
ParentNode (optional)
Root element to search for date range pickers. Defaults to document.
input[type="date"]
native date inputs
The first date input is treated as the start date and the last date input is treated as the end date.

Example

html
<script type="module">
  import { enhanceLumenDateRangePickers } from '@santi020k/lumen-elements/define'

  enhanceLumenDateRangePickers()
</script>

<section data-ui-date-range-picker class="ui-date-range-picker">
  <input class="ui-input ui-date-picker" type="date" aria-label="Start date" />
  <input class="ui-input ui-date-picker" type="date" aria-label="End date" />
</section>
<script type="module">
  import { enhanceLumenDateRangePickers } from '@santi020k/lumen-elements/define'

  enhanceLumenDateRangePickers()
</script>

<section data-ui-date-range-picker class="ui-date-range-picker">
  <input class="ui-input ui-date-picker" type="date" aria-label="Start date" />
  <input class="ui-input ui-date-picker" type="date" aria-label="End date" />
</section>

enhanceLumenInputOTPs

Enhances elements marked with [data-ui-input-otp] or <lumen-input-otp> with a real native input, visual segments, sanitized input, paste handling, and caret navigation.

Signature / AttributeDescription
root
ParentNode (optional)
Root element to search for OTP fields. Defaults to document.
length
attribute
Number of OTP segments to create. Defaults to 6.
value
attribute
Initial value copied to the generated native input.
name
attribute
Forwarded to the generated native input for form submission.

Example

html
<script type="module">
  import { enhanceLumenInputOTPs } from '@santi020k/lumen-elements/define'

  enhanceLumenInputOTPs()
</script>

<lumen-input-otp
  aria-label="Verification code"
  length="6"
  name="code"
></lumen-input-otp>
<script type="module">
  import { enhanceLumenInputOTPs } from '@santi020k/lumen-elements/define'

  enhanceLumenInputOTPs()
</script>

<lumen-input-otp
  aria-label="Verification code"
  length="6"
  name="code"
></lumen-input-otp>

enhanceLumenResizable

Enhances elements marked with [data-ui-resizable] with pane sizing, generated separator handles, pointer resizing, keyboard resizing, and double-click reset.

Signature / AttributeDescription
root
ParentNode (optional)
Root element to search for resizable groups. Defaults to document.
data-ui-resizable-default-sizes
comma-separated percentages
Initial pane sizes normalized to 100%.
data-ui-resizable-min-size
number or comma list
Minimum pane size percentage. Defaults to 12.
data-ui-resizable-max-size
number or comma list
Maximum pane size percentage. Defaults to 88.
data-orientation
"horizontal" | "vertical"
Resize axis. Defaults to horizontal.

Example

html
<script type="module">
  import { enhanceLumenResizable } from '@santi020k/lumen-elements/define'

  enhanceLumenResizable()
</script>

<lumen-resizable data-ui-resizable-default-sizes="30,70">
  <aside>Navigation</aside>
  <main>Editor</main>
</lumen-resizable>
<script type="module">
  import { enhanceLumenResizable } from '@santi020k/lumen-elements/define'

  enhanceLumenResizable()
</script>

<lumen-resizable data-ui-resizable-default-sizes="30,70">
  <aside>Navigation</aside>
  <main>Editor</main>
</lumen-resizable>

enhanceLumenRichTextEditors

Enhances elements marked with [data-ui-rich-text-editor] with toolbar command execution via document.execCommand. Works without registering custom elements.

Signature / AttributeDescription
root
ParentNode (optional)
Root element to search for editors. Defaults to document.
data-ui-command
attribute
Set on toolbar buttons to specify the command name (bold, italic, insertUnorderedList, etc.).

Example

html
<script type="module">
  import { enhanceLumenRichTextEditors } from '@santi020k/lumen-elements/define'

  enhanceLumenRichTextEditors()
</script>

<section data-ui-rich-text-editor class="ui-rich-text-editor">
  <div role="toolbar">
    <button data-ui-command="bold" class="ui-button ui-button--icon">B</button>
    <button data-ui-command="italic" class="ui-button ui-button--icon">I</button>
  </div>
  <div contenteditable data-ui-rich-text-editable>
    <p>Start writing...</p>
  </div>
</section>
<script type="module">
  import { enhanceLumenRichTextEditors } from '@santi020k/lumen-elements/define'

  enhanceLumenRichTextEditors()
</script>

<section data-ui-rich-text-editor class="ui-rich-text-editor">
  <div role="toolbar">
    <button data-ui-command="bold" class="ui-button ui-button--icon">B</button>
    <button data-ui-command="italic" class="ui-button ui-button--icon">I</button>
  </div>
  <div contenteditable data-ui-rich-text-editable>
    <p>Start writing...</p>
  </div>
</section>

LumenToast

Global singleton toast API available after calling defineLumenElements(). Create, update, and dismiss toast notifications from anywhere.

Signature / AttributeDescription
create(detail)
(ToastDetail) => string
Create a toast with title, description, variant, duration, placement, and optional action. Returns the toast id.
dismiss(id?)
(string?) => void
Dismiss a toast by id, or dismiss the most recent toast.
update(id, detail)
(string, ToastDetail) => void
Update an existing toast with new content.

Example

html
<script type="module">
  import { defineLumenElements, LumenToast } from '@santi020k/lumen-elements/define'

  defineLumenElements()

  document.querySelector('#notify').addEventListener('click', () => {
    LumenToast.create({
      title: 'Saved',
      description: 'Your changes are live.',
      variant: 'success',
      duration: 5000,
      placement: 'bottom-right'
    })
  })
</script>

<lumen-sonner aria-label="Notifications"></lumen-sonner>
<lumen-button id="notify">Show toast</lumen-button>
<script type="module">
  import { defineLumenElements, LumenToast } from '@santi020k/lumen-elements/define'

  defineLumenElements()

  document.querySelector('#notify').addEventListener('click', () => {
    LumenToast.create({
      title: 'Saved',
      description: 'Your changes are live.',
      variant: 'success',
      duration: 5000,
      placement: 'bottom-right'
    })
  })
</script>

<lumen-sonner aria-label="Notifications"></lumen-sonner>
<lumen-button id="notify">Show toast</lumen-button>

Custom events

Lumen elements dispatch CustomEvents that you can listen for on the document or on specific elements.

Signature / AttributeDescription
ui:toast
CustomEvent<ToastDetail>
Dispatched on document when a toast is created. Listen on document to handle toasts globally.
ui:validate
CustomEvent<{ control, form, value }>
Dispatched during form validation for each control.
ui:valid
CustomEvent<{ form, controls? }>
Dispatched when a form passes validation.
ui:invalid
CustomEvent<{ form, control?, controls? }>
Dispatched when a form fails validation.
ui:editor-command
CustomEvent<{ command }>
Dispatched when a rich text editor command is executed.
ui:toast-action
CustomEvent<{ event?, value? }>
Dispatched when a toast action button is clicked.

Example

html
<script type="module">
  // Listen for toast events globally
  document.addEventListener('ui:toast', (event) => {
    console.log('Toast created:', event.detail.title)
  })

  // Listen for form validation events
  document.querySelector('form').addEventListener('ui:invalid', (event) => {
    console.log('Invalid controls:', event.detail.controls)
  })

  // Listen for rich text commands
  document.addEventListener('ui:editor-command', (event) => {
    console.log('Command executed:', event.detail.command)
  })
</script>
<script type="module">
  // Listen for toast events globally
  document.addEventListener('ui:toast', (event) => {
    console.log('Toast created:', event.detail.title)
  })

  // Listen for form validation events
  document.querySelector('form').addEventListener('ui:invalid', (event) => {
    console.log('Invalid controls:', event.detail.controls)
  })

  // Listen for rich text commands
  document.addEventListener('ui:editor-command', (event) => {
    console.log('Command executed:', event.detail.command)
  })
</script>