Components
Input
Text inputs with shared field tokens and native validation styling.
Inputs use the .ui-input class and share --ui-field-* design tokens. Validation styles trigger via :user-invalid on blur or submit. Wrap in .ui-field for label, hint, and error message layouts.
Default
Loading components…
<div class="ui-field"> <label data-slot="field-label" for="f-name">Name</label> <input class="ui-input" id="f-name" name="name" type="text" inputmode="text" placeholder="Ada Lovelace" autocomplete="name" autocapitalize="words" enterkeyhint="next" /></div><div class="ui-field"> <label data-slot="field-label" for="f-email">Email</label> <input class="ui-input" id="f-email" name="email" type="email" inputmode="email" required placeholder="you@example.com" autocomplete="email" autocapitalize="off" spellcheck="false" enterkeyhint="next" aria-describedby="f-email-hint" /> <div data-slot="field-description"> <span data-slot="field-hint" id="f-email-hint" >We'll never sell or share your email address.</span > <span data-slot="field-error" role="alert">Please enter a valid email address.</span> </div></div><div class="ui-field"> <label data-slot="field-label" for="f-phone">Phone</label> <input class="ui-input" id="f-phone" name="phone" type="tel" inputmode="tel" placeholder="+1 (555) 012-3456" autocomplete="tel" enterkeyhint="next" /></div><div class="ui-field"> <label data-slot="field-label" for="f-date">Datetime</label> <input class="ui-input" id="f-date" name="date" type="datetime-local" inputmode="none" autocomplete="off" /></div>/** * input.css — Text input (.ui-input) * * @layer variables, components * @requires layers.css, _variables.css, fields.css, _reset.css * @uses ::-webkit-calendar-picker-indicator — date/time picker chrome (WebKit) * @uses mask — calendar icon (not background-image, for color: currentColor) * @tokens --ui-input-* (@layer variables) */@layer variables { :root { --ui-input-inline-size: 100%; --ui-input-min-inline-size: 16ch; --ui-input-padding-inline-start: var(--ui-field-padding); --ui-input-padding-inline-end: var(--ui-field-padding); --ui-input-font-size: var(--ui-field-font-size); --ui-input-line-height: var(--ui-field-line-height); --ui-input-border: 1px solid var(--ui-field-border); --ui-input-border-radius: var(--ui-field-radius); --ui-input-calendar-picker-color: currentColor; --ui-input-calendar-picker-icon-size: var(--step-4); --ui-input-calendar-picker-size: var(--step-6); --ui-input-calendar-picker-radius: var(--radius-sm); --ui-input-calendar-picker-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Crect width='256' height='256' fill='none'/%3E%3Crect x='40' y='40' width='176' height='176' rx='8' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3Cline x1='176' y1='24' x2='176' y2='56' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3Cline x1='80' y1='24' x2='80' y2='56' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3Cline x1='40' y1='88' x2='216' y2='88' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3C/svg%3E"); }}@layer zazz.components { /* =========================================================================== TEXT INPUTS — .ui-input - One class for every text-like type (text, search, email, number, date, …); the type only changes the picker/keyboard, not the box. - Shares the --ui-field-* tokens defined in fields.css so it aligns with .ui-select, .ui-textarea, and .ui-button. =========================================================================== */ .ui-input { inline-size: var(--ui-input-inline-size); min-inline-size: var(--ui-input-min-inline-size); block-size: var(--ui-field-height); padding-inline-start: var(--ui-input-padding-inline-start); padding-inline-end: var(--ui-input-padding-inline-end); font-size: var(--ui-input-font-size); line-height: var(--ui-input-line-height); color: var(--ui-field-foreground); background-color: var(--ui-field-background); border: var(--ui-input-border); border-radius: var(--ui-input-border-radius); /* ring renders as box-shadow; transparent outline twin keeps focus visible in forced-colors / high-contrast modes */ --_ring-offset-width: 0px; --_ring-width: 0px; --_ring: color-mix(in oklch, var(--ui-field-ring-color) var(--ring-opacity), transparent); box-shadow: 0 0 0 var(--_ring-offset-width) var(--ring-offset-color), 0 0 0 calc(var(--_ring-offset-width) + var(--_ring-width)) var(--_ring, var(--ring)); outline: var(--outline-width) var(--outline-style) transparent; outline-offset: var(--outline-offset); transition: var(--default-transition); } .ui-input:hover { border-color: var(--ui-field-border--hover); background-color: var(--ui-field-background--hover); } .ui-input:focus-within { background-color: var(--ui-field-background--focus); border-color: var(--ui-field-border--focus); --_ring-offset-width: var(--ring-offset-width); --_ring-width: var(--ring-width); outline-color: transparent; } .ui-input[type="date"], .ui-input[type="time"], .ui-input[type="datetime-local"] { --ui-input-padding-inline-end: var(--step-1_5); } /* Native date/time controls keep their picker indicator tinted to the text */ .ui-input::-webkit-calendar-picker-indicator { cursor: pointer; -webkit-appearance: none; margin: 0; padding: 0; inline-size: var(--ui-input-calendar-picker-size); block-size: var(--ui-input-calendar-picker-size); border-radius: var(--ui-input-calendar-picker-radius); transition: opacity var(--default-transition-duration) var(--default-transition-timing-function), display var(--default-transition-duration) var(--default-transition-timing-function) allow-discrete; mask: var(--ui-input-calendar-picker-mask) no-repeat center / var(--ui-input-calendar-picker-icon-size); background-size: var(--ui-input-calendar-picker-icon-size); background-color: var(--ui-input-calendar-picker-color); background-repeat: no-repeat; background-position: center; } .ui-input::-webkit-calendar-picker-indicator:is(:hover) { opacity: 0.5; }}Leading icon
Loading components…
<label class="ui-input-group"> <input class="ui-input" type="text" placeholder="Placeholder" /> <span data-slot="input-group-addon"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" > <line x1="4" y1="6" x2="20" y2="6" /> <line x1="4" y1="12" x2="20" y2="12" /> <line x1="4" y1="18" x2="20" y2="18" /> </svg> </span></label>/** * input.css — Text input (.ui-input) * * @layer variables, components * @requires layers.css, _variables.css, fields.css, _reset.css * @uses ::-webkit-calendar-picker-indicator — date/time picker chrome (WebKit) * @uses mask — calendar icon (not background-image, for color: currentColor) * @tokens --ui-input-* (@layer variables) */@layer variables { :root { --ui-input-inline-size: 100%; --ui-input-min-inline-size: 16ch; --ui-input-padding-inline-start: var(--ui-field-padding); --ui-input-padding-inline-end: var(--ui-field-padding); --ui-input-font-size: var(--ui-field-font-size); --ui-input-line-height: var(--ui-field-line-height); --ui-input-border: 1px solid var(--ui-field-border); --ui-input-border-radius: var(--ui-field-radius); --ui-input-calendar-picker-color: currentColor; --ui-input-calendar-picker-icon-size: var(--step-4); --ui-input-calendar-picker-size: var(--step-6); --ui-input-calendar-picker-radius: var(--radius-sm); --ui-input-calendar-picker-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Crect width='256' height='256' fill='none'/%3E%3Crect x='40' y='40' width='176' height='176' rx='8' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3Cline x1='176' y1='24' x2='176' y2='56' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3Cline x1='80' y1='24' x2='80' y2='56' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3Cline x1='40' y1='88' x2='216' y2='88' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3C/svg%3E"); }}@layer zazz.components { /* =========================================================================== TEXT INPUTS — .ui-input - One class for every text-like type (text, search, email, number, date, …); the type only changes the picker/keyboard, not the box. - Shares the --ui-field-* tokens defined in fields.css so it aligns with .ui-select, .ui-textarea, and .ui-button. =========================================================================== */ .ui-input { inline-size: var(--ui-input-inline-size); min-inline-size: var(--ui-input-min-inline-size); block-size: var(--ui-field-height); padding-inline-start: var(--ui-input-padding-inline-start); padding-inline-end: var(--ui-input-padding-inline-end); font-size: var(--ui-input-font-size); line-height: var(--ui-input-line-height); color: var(--ui-field-foreground); background-color: var(--ui-field-background); border: var(--ui-input-border); border-radius: var(--ui-input-border-radius); /* ring renders as box-shadow; transparent outline twin keeps focus visible in forced-colors / high-contrast modes */ --_ring-offset-width: 0px; --_ring-width: 0px; --_ring: color-mix(in oklch, var(--ui-field-ring-color) var(--ring-opacity), transparent); box-shadow: 0 0 0 var(--_ring-offset-width) var(--ring-offset-color), 0 0 0 calc(var(--_ring-offset-width) + var(--_ring-width)) var(--_ring, var(--ring)); outline: var(--outline-width) var(--outline-style) transparent; outline-offset: var(--outline-offset); transition: var(--default-transition); } .ui-input:hover { border-color: var(--ui-field-border--hover); background-color: var(--ui-field-background--hover); } .ui-input:focus-within { background-color: var(--ui-field-background--focus); border-color: var(--ui-field-border--focus); --_ring-offset-width: var(--ring-offset-width); --_ring-width: var(--ring-width); outline-color: transparent; } .ui-input[type="date"], .ui-input[type="time"], .ui-input[type="datetime-local"] { --ui-input-padding-inline-end: var(--step-1_5); } /* Native date/time controls keep their picker indicator tinted to the text */ .ui-input::-webkit-calendar-picker-indicator { cursor: pointer; -webkit-appearance: none; margin: 0; padding: 0; inline-size: var(--ui-input-calendar-picker-size); block-size: var(--ui-input-calendar-picker-size); border-radius: var(--ui-input-calendar-picker-radius); transition: opacity var(--default-transition-duration) var(--default-transition-timing-function), display var(--default-transition-duration) var(--default-transition-timing-function) allow-discrete; mask: var(--ui-input-calendar-picker-mask) no-repeat center / var(--ui-input-calendar-picker-icon-size); background-size: var(--ui-input-calendar-picker-icon-size); background-color: var(--ui-input-calendar-picker-color); background-repeat: no-repeat; background-position: center; } .ui-input::-webkit-calendar-picker-indicator:is(:hover) { opacity: 0.5; }}Trailing icon
Loading components…
<label class="ui-input-group"> <input class="ui-input" type="search" placeholder="Search…" aria-label="Search" /> <span data-slot="input-group-addon" data-align="inline-end"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" > <circle cx="11" cy="11" r="8" /> <line x1="21" y1="21" x2="16.65" y2="16.65" /> </svg> </span></label>/** * input.css — Text input (.ui-input) * * @layer variables, components * @requires layers.css, _variables.css, fields.css, _reset.css * @uses ::-webkit-calendar-picker-indicator — date/time picker chrome (WebKit) * @uses mask — calendar icon (not background-image, for color: currentColor) * @tokens --ui-input-* (@layer variables) */@layer variables { :root { --ui-input-inline-size: 100%; --ui-input-min-inline-size: 16ch; --ui-input-padding-inline-start: var(--ui-field-padding); --ui-input-padding-inline-end: var(--ui-field-padding); --ui-input-font-size: var(--ui-field-font-size); --ui-input-line-height: var(--ui-field-line-height); --ui-input-border: 1px solid var(--ui-field-border); --ui-input-border-radius: var(--ui-field-radius); --ui-input-calendar-picker-color: currentColor; --ui-input-calendar-picker-icon-size: var(--step-4); --ui-input-calendar-picker-size: var(--step-6); --ui-input-calendar-picker-radius: var(--radius-sm); --ui-input-calendar-picker-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Crect width='256' height='256' fill='none'/%3E%3Crect x='40' y='40' width='176' height='176' rx='8' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3Cline x1='176' y1='24' x2='176' y2='56' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3Cline x1='80' y1='24' x2='80' y2='56' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3Cline x1='40' y1='88' x2='216' y2='88' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='16'/%3E%3C/svg%3E"); }}@layer zazz.components { /* =========================================================================== TEXT INPUTS — .ui-input - One class for every text-like type (text, search, email, number, date, …); the type only changes the picker/keyboard, not the box. - Shares the --ui-field-* tokens defined in fields.css so it aligns with .ui-select, .ui-textarea, and .ui-button. =========================================================================== */ .ui-input { inline-size: var(--ui-input-inline-size); min-inline-size: var(--ui-input-min-inline-size); block-size: var(--ui-field-height); padding-inline-start: var(--ui-input-padding-inline-start); padding-inline-end: var(--ui-input-padding-inline-end); font-size: var(--ui-input-font-size); line-height: var(--ui-input-line-height); color: var(--ui-field-foreground); background-color: var(--ui-field-background); border: var(--ui-input-border); border-radius: var(--ui-input-border-radius); /* ring renders as box-shadow; transparent outline twin keeps focus visible in forced-colors / high-contrast modes */ --_ring-offset-width: 0px; --_ring-width: 0px; --_ring: color-mix(in oklch, var(--ui-field-ring-color) var(--ring-opacity), transparent); box-shadow: 0 0 0 var(--_ring-offset-width) var(--ring-offset-color), 0 0 0 calc(var(--_ring-offset-width) + var(--_ring-width)) var(--_ring, var(--ring)); outline: var(--outline-width) var(--outline-style) transparent; outline-offset: var(--outline-offset); transition: var(--default-transition); } .ui-input:hover { border-color: var(--ui-field-border--hover); background-color: var(--ui-field-background--hover); } .ui-input:focus-within { background-color: var(--ui-field-background--focus); border-color: var(--ui-field-border--focus); --_ring-offset-width: var(--ring-offset-width); --_ring-width: var(--ring-width); outline-color: transparent; } .ui-input[type="date"], .ui-input[type="time"], .ui-input[type="datetime-local"] { --ui-input-padding-inline-end: var(--step-1_5); } /* Native date/time controls keep their picker indicator tinted to the text */ .ui-input::-webkit-calendar-picker-indicator { cursor: pointer; -webkit-appearance: none; margin: 0; padding: 0; inline-size: var(--ui-input-calendar-picker-size); block-size: var(--ui-input-calendar-picker-size); border-radius: var(--ui-input-calendar-picker-radius); transition: opacity var(--default-transition-duration) var(--default-transition-timing-function), display var(--default-transition-duration) var(--default-transition-timing-function) allow-discrete; mask: var(--ui-input-calendar-picker-mask) no-repeat center / var(--ui-input-calendar-picker-icon-size); background-size: var(--ui-input-calendar-picker-icon-size); background-color: var(--ui-input-calendar-picker-color); background-repeat: no-repeat; background-position: center; } .ui-input::-webkit-calendar-picker-indicator:is(:hover) { opacity: 0.5; }}