Single-line text field with the shared label, help and error lines. Form-associated: it posts name=value with a plain form and binds to React, Vue (v-model) and Angular forms. Always give it a label; for an unlabeled toolbar search, use sui-icon-field.
Usage
<sui-input-text label="Customer email" name="email" type="email" placeholder="you@company.com" help="Receipts are sent here."></sui-input-text>
<script type="module">
import { defineCustomElements } from "@shineui/core/loader";
import "@shineui/core/shineui.css";
defineCustomElements();
const el = document.querySelector("sui-input-text");
el.addEventListener("suiChange", (e) => console.log(e.detail));
</script>
import { SuiInputText } from "@shineui/react";
import "@shineui/core/shineui.css";
export function Example() {
return <SuiInputText label="Customer email" name="email" type="email" placeholder="you@company.com" help="Receipts are sent here." onSuiChange={(e) => console.log(e.detail)} />;
}
import { Component } from "@angular/core";
import { SuiInputText } from "@shineui/angular";
@Component({
standalone: true,
imports: [SuiInputText],
template: `<sui-input-text label="Customer email" name="email" type="email" placeholder="you@company.com" help="Receipts are sent here." (suiChange)="onChange($event)"></sui-input-text>`,
})
export class Example {
onChange(e: CustomEvent) { console.log(e.detail); }
}
Basic
The label is bound to the inner input, so clicking it focuses the field. Help text is wired through aria-describedby and read after the label.
<div style="max-width:340px">
<sui-input-text label="Customer email" name="email" type="email" placeholder="you@company.com" help="Receipts are sent here."></sui-input-text>
</div>
Sizes
md is the default, one height with every select, picker and button, so a form built from defaults lines up. lg is the roomier field for a sign-in or marketing page; sm packs into table rows.
The error line replaces help and carries role="alert", so it announces when it appears. A read-only field still posts its value; a disabled one does not.
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px">
<sui-input-text label="Customer email" required placeholder="you@company.com" help="Receipts are sent here."></sui-input-text>
<sui-input-text label="Customer" error="Customer is required."></sui-input-text>
<sui-input-text label="Terms" value="Net 30" disabled></sui-input-text>
<sui-input-text label="Invoice #" value="INV-1043" readonly help="Assigned automatically."></sui-input-text>
</div>
Named from context
A settings row already prints the term, so a label would double it. aria-label on the element names the input, and aria-labelledby names it from the term the row draws. A visible label wins over both, so the name a reader hears is always one on the page.
pattern and minlength are the native attributes, checked by the browser and reported as patternMismatch or tooShort with its own message. inputmode and enterkeyhint on the host reach the input; spellcheck and autocapitalize apply from the host. The validity methods answer as on a native input.
// setup(root): properties and events
setup(root) {
const zip = root.querySelector('#it-zip');
const out = root.querySelector('#it-out');
root.querySelector('#it-check').addEventListener('click', () => {
const ok = zip.checkValidity();
const flags = ['valueMissing', 'patternMismatch', 'tooShort', 'tooLong', 'typeMismatch', 'badInput', 'customError'].filter((k) => zip.validity[k]);
out.textContent = ok ? 'Valid.' : `Invalid: ${flags.join(', ') || 'see the message'}. ${zip.validationMessage}`;
});
root.querySelector('#it-taken').addEventListener('click', () => {
zip.setCustomValidity(zip.value ? `${zip.value} is already assigned.` : '');
out.textContent = zip.value ? 'Custom message set; check again, or clear it by emptying the field and marking again.' : 'Custom message cleared.';
});
}
In a form
Each field posts one entry under its host name. Empty posts an empty string, a disabled field posts nothing, and Reset restores the value each field mounted with.
// setup(root): properties and events
setup(root) {
const form = root.querySelector('#it-form');
const out = root.querySelector('#it-out');
form.addEventListener('submit', (e) => {
e.preventDefault();
out.textContent = [...new FormData(form)].map(([k, v]) => `${k}=${v || '(empty)'}`).join(' ');
});
form.addEventListener('reset', () => {
out.textContent = 'Reset. Submit to see what posts.';
});
}
Events
suiInput fires on every keystroke, suiChange on commit at blur or Enter. Both carry the current value as the detail. suiFocus and suiBlur follow the input, the pair every text field carries, so a host arms a hint on focus the same way on each.
Moves to the field and on to the next control; the host itself takes no tab stop.
Printable characters
Type into the native input; suiInput fires on every keystroke.
Enter
Submits the surrounding form, as a native input does.
API
<sui-input-text>
Properties
Property
Attribute
Type
Default
Description
autocomplete
autocomplete
stringstring | undefined
Native autocomplete hint. inputmode and enterkeyhint set on the host reach the input the same way, and spellcheck and autocapitalize on the host apply to it as they do to any descendant.
disabled
disabled
boolean
false
Disables the field.
error
error
stringstring | undefined
Error message; paints the field in the danger tone and sets aria-invalid.
help
help
stringstring | undefined
Help text under the field. Replaced by error when set.
invalid
invalid
boolean
false
Danger border without a message (validation handled elsewhere).
label
label
stringstring | undefined
Field label. Without one the field takes the host's aria-label or aria-labelledby as its name, for a settings row that already prints the term; a visible label wins over both.
maxLength
maxlength
numbernumber | undefined
Maximum number of characters, as the native maxlength.
minLength
minlength
numbernumber | undefined
Native minlength: a value shorter than this, once the user has typed, fails as tooShort.
name
name
stringstring | undefined
Form control name. Reflected: entry construction reads the content attribute, and the three framework bindings set props, so an unreflected name would post nothing.
pattern
pattern
stringstring | undefined
Native pattern: a regular expression the whole value must match. The browser checks it and the field reports patternMismatch on its validity, the way required reports valueMissing.
placeholder
placeholder
stringstring | undefined
Placeholder text.
readOnly
readonly
boolean
false
Display only: the text can be selected and copied but not edited; the field still posts its value.
required
required
boolean
false
Marks the field required (asterisk + valueMissing validity when empty).
size
size
"lg" | "md" | "sm"
'md'
Control height: sm 28 for table rows, md 34 for forms and toolbars (the default, shared with the select family and the buttons, so a form built from defaults is one height), lg 42 for a sign-in or marketing page.
Native input type. One union across the four elements that wrap a native text input.
value
value
string
''
Current value. Mutable; listen to suiInput / suiChange to observe edits.
Events
Event
Detail
React
Vue
Description
suiBlur
void
onSuiBlur
@sui-blur
Fires when the input loses focus; no detail. Does not bubble.
suiChange
string
onSuiChange
@sui-change
Fires on commit (blur or Enter, native change); detail is the final value.
suiFocus
void
onSuiFocus
@sui-focus
Fires when the input takes focus; no detail. Every text field carries the same pair, so a host arms a hint or a launcher the same way on each without listening for the native focusin. Does not bubble.
suiInput
string
onSuiInput
@sui-input
Fires on every keystroke; detail is the current value.
Methods
Method
Signature
Description
select()
select() => Promise<void>
Selects the field text.
setFocus()
setFocus() => Promise<void>
Moves keyboard focus into the field.
Types
SuiInputTypetypeThe native type values the text-input skin draws. One union for the whole family: the four elements that wrap a native text input each listed a different subset in prose, which read as a rule and was not one. Anything outside this set has its own element (sui-input-number, sui-date-picker, sui-color-picker) or its own skin.
No members.
Theming
Every design token this element can render with, read from its own stylesheets and the ones it imports. Set a token on :root or on any ancestor and every use below follows it. The values shown are the ones in the theme you are viewing. The list is read per stylesheet, so an element that imports a shared drawing module lists that module's tokens too, whether or not it paints with all of them.