Skip to content

Input <input>

Inputs let users enter and edit text, numbers, dates, and other single-line values.

HTML tag<input>
Native
Progressive
Plain
Shadow-DOM
Native element
html
<l-form-field>
  <label>Email</label>
  <input
    type="email"
    placeholder="jane@acme.com"
  />
  <p class="l-hint">We'll never share it.</p>
</l-form-field>

l-form-field auto-styles a bare text <input> and wires the accessibility (label, hint, error, aria-*). Standalone, apply .l-input to the input yourself.

Options

Type

.l-input styles every text-like type. date and time get a custom picker icon; search gets a custom clear button — all with zero JavaScript.

Code
html
<div class="grid gap-4 max-w-sm">
  <l-form-field>
    <label>Text</label>
    <input
      type="text"
      placeholder="Placeholder text"
    />
  </l-form-field>
  <l-form-field>
    <label>Number</label>
    <input
      type="number"
      placeholder="Placeholder text"
    />
  </l-form-field>
  <l-form-field>
    <label>Password</label>
    <input
      type="password"
      value="supersecret"
    />
  </l-form-field>
  <l-form-field>
    <label>Date</label>
    <input type="date" />
  </l-form-field>
  <l-form-field>
    <label>Time</label>
    <input type="time" />
  </l-form-field>
  <l-form-field>
    <label>Search</label>
    <input
      type="search"
      value="This a value"
    />
  </l-form-field>
</div>

States

Native disabled and readonly. Invalid is styled via :user-invalid (after interaction) or by setting aria-invalid="true" — inside l-form-field this is managed for you.

Enter a valid email address.

Code
html
<div class="grid gap-4 max-w-sm">
  <l-form-field>
    <label>Default</label>
    <input
      type="text"
      placeholder="Placeholder text"
    />
  </l-form-field>
  <l-form-field>
    <label>Read-only</label>
    <input
      type="text"
      value="Read-only value"
      readonly
    />
  </l-form-field>
  <l-form-field>
    <label>Disabled</label>
    <input
      type="text"
      value="Disabled value"
      disabled
    />
  </l-form-field>
  <l-form-field>
    <label>Invalid</label>
    <input
      type="email"
      value="not-an-email"
      aria-invalid="true"
    />
    <p class="l-error">Enter a valid email address.</p>
  </l-form-field>
</div>

Size & radius

Override --height for the control height and --border-radius for the corners.

Password toggle

Add password-toggle on l-input-group — a show/hide button is injected when JavaScript loads (aria-pressed, localized label, Eye/EyeOff icon). Without JavaScript the field stays a plain password input.

Code
html
<div class="max-w-sm">
  <l-form-field>
    <label>Password</label>
    <l-input-group password-toggle>
      <input
        type="password"
        value="supersecret"
        autocomplete="current-password"
      />
    </l-input-group>
  </l-form-field>
</div>

Examples

Icons & units

A replaced <input> can't hold children, so wrap it in l-input-group: the group draws the border and the inner input becomes borderless — no class needed. Children render in DOM order, so an <l-icon> before the input is a leading adornment, a <span> after it is a trailing one.

cm
Code
html
<div class="grid gap-4 max-w-sm">
  <l-form-field>
    <label>Search</label>
    <l-input-group>
      <l-icon name="lucide:search"></l-icon>
      <input
        type="search"
        placeholder="Search"
      />
    </l-input-group>
  </l-form-field>
  <l-form-field>
    <label>Height</label>
    <l-input-group>
      <input
        type="number"
        placeholder="Placeholder text"
      />
      <span>cm</span>
    </l-input-group>
  </l-form-field>
  <l-form-field>
    <label>Email</label>
    <l-input-group>
      <l-icon name="lucide:mail"></l-icon>
      <input
        type="email"
        placeholder="jane@acme.com"
      />
    </l-input-group>
  </l-form-field>
</div>

With a hint

.l-hint adds always-visible helper text, linked to the control via aria-describedby.

We'll never share it.

Code
html
<l-form-field>
  <label>Email</label>
  <input
    type="email"
    placeholder="jane@acme.com"
  />
  <p class="l-hint">We'll never share it.</p>
</l-form-field>

Accessibility

Criteria

Accessible name

Must have an associated <label> (wrap the input or use for/id)

WCAG1.3.1
RGAA11.1
Input purpose

Set type and autocomplete so the field communicates its purpose and benefits from autofill

WCAG1.3.5
RGAA11.13
Focus visible

Keyboard focus shows a 2px outline via :focus-visible

WCAG2.4.7
RGAA10.7
Errors identified

aria-invalid marks the field; pair it with a visible message linked via aria-describedby

WCAG3.3.1
RGAA11.10
Required state

Native required communicates a mandatory field to assistive tech

WCAG3.3.2
RGAA11.10

Keyboard interactions

Tab
Moves focus to the input
Esc
On `type=search`, clears the field (native)

API reference

Importing

css
@import 'luxen-ui/css/input';
js
import 'luxen-ui/input-group';

The CSS covers everything except the password toggle; the JS import upgrades l-input-group with its behavior.

Attributes & Properties

typetext | search | number | password | email | url | tel | date | timeAttribute
Native input type. date/time get custom picker icons; search gets a custom clear button.
data-sizexs | sm | md | lg | xlAttribute
Control height on the shared --l-size-control-* scale (default md). Affects only the height, not the label or hint/error.
placeholderAttribute
Native placeholder text.
disabledAttribute
Disables the input.
requiredAttribute
Marks the input as required for form submission.
readonlyAttribute
Makes the input read-only.
aria-invalidAttribute
Set to true to force the invalid style (otherwise applied via :user-invalid). l-form-field manages this automatically.

CSS classes

.l-inputClass
Base input style, applied to a text-like <input> (text, search, number, password, email, url, tel, date, time, …). Inside l-form-field or l-input-group a bare text input is auto-styled, so the class is optional there.

CSS custom properties

--heightdefault:var(--l-form-control-height)Custom property
Control height.
--border-radiusdefault:var(--l-form-control-border-radius)Custom property
Control border radius.
--calendar-iconCustom property
Date picker glyph as a url(). Masked, so color is taken from the control, not the image.
--clock-iconCustom property
Time picker glyph as a url().
--clear-iconCustom property
Search clear glyph as a url().

Input group

password-togglebooleandefault:falseProperty
Inject a show/hide toggle button after the inner input[type="password"].
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | undefineddefault:mdProperty
Control size — maps the height to the shared --l-size-control-* scale ().
.l-input-group-toggleClass
The injected show/hide password button.