Components

All components are semantic-first. Most work with zero classes — just write correct HTML.

Button

Style native <button> elements via data-variant. Loading state via aria-busy.

Variants
<button>Default</button> <button data-variant="brand">Brand</button> <button data-variant="outline">Outline</button> <button data-variant="ghost">Ghost</button> <button data-variant="danger">Danger</button>
Sizes
<button class="sm" data-variant="brand">Small</button> <button data-variant="brand">Default</button> <button class="lg" data-variant="brand">Large</button>
Loading state
<button data-variant="brand" aria-busy="true">Deploying…</button>
Button group
<div class="btn-group"> <button data-variant="outline">Day</button> <button data-variant="outline">Week</button> <button>Month</button> </div>

Inputs

Native inputs styled automatically. Use .field wrapper for label + hint + validation. aria-invalid="true" triggers error state.

Used in your dashboard URL.
Invalid API key format.
<div class="field"> <label>Project name</label> <input type="text" placeholder="my-saas-app" /> <span class="field-hint">Used in your dashboard URL.</span> </div> <!-- Error state --> <div class="field"> <label>API Key</label> <input aria-invalid="true" /> <span class="field-error">Invalid API key.</span> </div>
Input with icon / group
https://
<!-- Icon input --> <div class="input-wrap"> <svg class="input-icon"></svg> <input type="search" placeholder="Search…" /> </div> <!-- Input group --> <div class="input-group"> <span>https://</span> <input type="text" placeholder="your-app.com" /> <button>Check</button> </div>

Checkbox · Radio

Fully custom-styled, accessible. Wrap with .checkbox-label or .radio-label for clickable labels.

<label class="checkbox-label"> <input type="checkbox" checked /> Enable logging </label> <label class="radio-label"> <input type="radio" name="plan" /> Pro </label>

Switch

A checkbox with role="switch". No JS needed.

<label class="checkbox-label"> <input type="checkbox" role="switch" checked /> Dark mode </label>

Card

Surface container with .card. Variants: glass, subtle. Stat cards for dashboards.

Project Alpha

Last deploy 2 min ago

Production build is healthy. 3 services running.

Glass card

Backdrop blur, ideal for overlay UIs.

Stat cards
Total users
12,849
↑ 8.2%
MRR
$4,210
↑ 23%
Churn rate
2.4%
↓ 0.3%
<div class="stat-card"> <div class="stat-label">Total users</div> <div class="stat-value">12,849</div> <div class="stat-delta up">↑ 8.2%</div> </div>

Table

Wrap in .table-wrap for overflow + rounded border. Add data-sort to <th> for sort indicators.

ModelProviderTokens/sStatus
claude-sonnet-4-6Anthropic94 Live
gpt-4oOpenAI78 Live
llama-3.3-70bGroq312 Beta
<div class="table-wrap"> <table> <thead><tr> <th data-sort="asc">Model</th> <th>Status</th> </tr></thead> <tbody><tr> <td>claude-sonnet-4-6</td> <td><span class="badge dot" data-variant="success">Live</span></td> </tr></tbody> </table> </div>

Alert

Use data-variant for semantic color. Add .alert-title for bold heading. SVG icon is optional.

Rate limit approaching
You've used 85% of your monthly tokens.
Deployment successful
v2.4.1 is live on production.
Breaking change in v3
The --accent variable was renamed.
Build failed
TypeScript errors in 3 files.
<div class="alert" data-variant="success"> <svg class="alert-icon"></svg> <div class="alert-content"> <div class="alert-title">Deployed</div> v2.4.1 is live. </div> </div>

Badge

Inline status chips. Add .dot for a leading indicator dot. Sizes: default, .md, .lg.

Default Brand Live Pending Error Beta Medium Large
<span class="badge dot" data-variant="success">Live</span> <span class="badge" data-variant="warning">Pending</span> <span class="badge md" data-variant="brand">New</span>

Toast

JavaScript API via lux.toast(). Shorthand: lux.toast.success(), .error(), .warning(), .info().

// Shorthand variants lux.toast.success({ title: 'Deployed!', message: 'v2.4.1 is live.' }); lux.toast.error({ title: 'Build failed', message: 'Check CI logs.' }); lux.toast.warning('Rate limit at 85%.'); lux.toast.info('Session expires soon.'); // Full options lux.toast({ title: 'Done', message: '…', variant: 'success', duration: 4000 });

Progress · Spinner

Native <progress> element, styled with CSS. Spinner via .spinner.

Uploading model weights64%
<progress value="64" max="100"></progress> <progress value="64" max="100" class="lg"></progress> <div class="spinner"></div> <div class="spinner lg"></div>

Skeleton

Loading placeholders via .skeleton. Variants: .text, .title, .circle, .card.

<div class="skeleton circle" style="width:40px;height:40px"></div> <div class="skeleton title" style="width:60%"></div> <div class="skeleton card"></div>

Tabs

<lux-tabs> web component. Arrow keys navigate. Two styles: pill (default) and underline.

Overview: 48,291 API calls this month.

Model list.

<lux-tabs> <div class="tabs-list"> <button role="tab" aria-selected="true" aria-controls="panel1">Overview</button> <button role="tab" aria-controls="panel2">Usage</button> </div> <div id="panel1" role="tabpanel"></div> <div id="panel2" role="tabpanel" hidden></div> </lux-tabs>

Accordion

Pure CSS using native <details> / <summary>. No JS. Add .flush for borderless style.

What models are supported?
Any OpenAI-compatible model — Anthropic, OpenAI, Groq, Ollama, and more. Configure via environment variables.
Is there a free tier?
Yes. Up to 10,000 tokens/month on the Starter plan. No credit card required.
How do I self-host?
Clone the repo, run docker compose up, and configure your .env. Docs cover every option.
<div class="accordion"> <details open> <summary>What models are supported?</summary> <div class="accordion-body">Any OpenAI-compatible model.</div> </details> </div>

Avatar

Image or initials. Sizes: .sm, default, .lg, .xl. Group with .avatar-group.

SR
MK
AL
JD
SR
MK
AL
+4
<div class="avatar">SR</div> <div class="avatar lg"><img src="photo.jpg" alt="User" /></div> <div class="avatar-group"> <div class="avatar">SR</div> <div class="avatar">MK</div> <div class="avatar">+4</div> </div>

Tooltip

Pure CSS via data-tooltip attribute. No JS. Position with data-tip-pos="bottom".

Beta
<button data-tooltip="Deploys to production">Deploy</button> <button data-tooltip="Copy" data-tip-pos="bottom"></button>

Dialog · Sheet

Native <dialog>. Open with data-dialog="id", close with data-dialog-close. Sheet slides from the right.

Confirm deployment

This will push v2.4.1 to production. The rollback window is 30 minutes.

3 pending database migrations will run automatically.

Notification settings

Choose how and when you're notified.

<button data-dialog="my-modal">Open</button> <dialog id="my-modal"> <div class="dialog-header"><h3>Confirm</h3></div> <div class="dialog-body"></div> <div class="dialog-footer"> <button data-dialog-close>Cancel</button> <button data-variant="brand">Confirm</button> </div> </dialog> <!-- Sheet --> <dialog id="my-sheet" data-variant="sheet"></dialog>

Typography

All heading levels, body text, inline elements, and code blocks are styled automatically.

Heading 1

Heading 2

Heading 3

Heading 4

Body text. The quick brown fox jumps over the lazy dog. Bold, italic, and linked text.

Inline code, keyboard shortcut ⌘K, and highlighted text.

Semantic HTML is the foundation. Lux makes it beautiful.

const result = await lux.ai.complete({ model: 'claude-sonnet-4-6', prompt });