Skip to content
ShineUI
Install

IftaLabel

The label lives inside.

<sui-ifta-label>Text inputsStable

About

Text field with the label inside the border, small and uppercase, above the value: the in-field top-aligned pattern for dense record editors. Form-associated: it posts name=value and binds to React, Vue (v-model) and Angular forms.

Usage

<sui-ifta-label label="Invoice #" name="invoice" value="INV-1043"></sui-ifta-label> <script type="module"> import { defineCustomElements } from "@shineui/core/loader"; import "@shineui/core/shineui.css"; defineCustomElements(); const el = document.querySelector("sui-ifta-label"); el.addEventListener("suiChange", (e) => console.log(e.detail)); </script>
import { SuiIftaLabel } from "@shineui/react"; import "@shineui/core/shineui.css"; export function Example() { return <SuiIftaLabel label="Invoice #" name="invoice" value="INV-1043" onSuiChange={(e) => console.log(e.detail)} />; }
<script setup> import { SuiIftaLabel } from "@shineui/vue"; import "@shineui/core/shineui.css"; const onChange = (e) => console.log(e.detail); </script> <template> <SuiIftaLabel label="Invoice #" name="invoice" value="INV-1043" @sui-change="onChange" /> </template>
import { Component } from "@angular/core"; import { SuiIftaLabel } from "@shineui/angular"; @Component({ standalone: true, imports: [SuiIftaLabel], template: `<sui-ifta-label label="Invoice #" name="invoice" value="INV-1043" (suiChange)="onChange($event)"></sui-ifta-label>`, }) export class Example { onChange(e: CustomEvent) { console.log(e.detail); } }

Basic

The small uppercase label sits inside the border above the value. It is a real label bound to the input, and a click anywhere in the box focuses the field.

<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;max-width:480px"> <sui-ifta-label label="Invoice #" name="invoice" value="INV-1043"></sui-ifta-label> <sui-ifta-label label="PO number" name="po" placeholder="PO-0000"></sui-ifta-label> </div>

States

The in-field label is the field label, so help and error render on the shared lines below. The error line carries role="alert".

<div style="display:grid;gap:14px;max-width:480px"> <sui-ifta-label label="PO number" placeholder="PO-0000" help="Optional on a credit memo." maxlength="12"></sui-ifta-label> <sui-ifta-label label="Invoice #" value="INV-1043" error="Invoice # is already used."></sui-ifta-label> <sui-ifta-label label="Posted on" value="Aug 14, 2026" readonly help="Set when the invoice posted."></sui-ifta-label> <sui-ifta-label label="Ledger" value="4402 Operating" disabled></sui-ifta-label> </div>

In a form

Each field posts one entry under its host name. A disabled field posts nothing, and Reset restores the value each field mounted with.

Submit to see what posts.
<form id="ifta-form" style="display:grid;grid-template-columns:1fr 1fr;gap:14px;max-width:480px"> <sui-ifta-label label="Invoice #" name="invoice" value="INV-1043" required></sui-ifta-label> <sui-ifta-label label="PO number" name="po" placeholder="PO-0000"></sui-ifta-label> <sui-ifta-label label="Ledger" name="ledger" value="4402 Operating" disabled></sui-ifta-label> <div style="display:flex;gap:8px;align-self:end"> <sui-button type="submit" variant="brand" label="Save record"></sui-button> <sui-button type="reset" variant="outline" label="Reset"></sui-button> </div> <output id="ifta-out" style="grid-column:1/-1;font:460 13px/1.6 var(--font-sans);color:var(--ink-muted)">Submit to see what posts.</output> </form>
// setup(root): properties and events setup(root) { const form = root.querySelector('#ifta-form'); const out = root.querySelector('#ifta-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.

Idle.
<div style="display:grid;gap:10px;max-width:340px"> <sui-ifta-label id="ifta-events" label="PO number" name="po" placeholder="PO-0000"></sui-ifta-label> <span id="ifta-log" style="font:460 13px/1.6 var(--font-sans);color:var(--ink-muted)">Idle.</span> </div>
// setup(root): properties and events setup(root) { const log = root.querySelector('#ifta-log'); const el = root.querySelector('#ifta-events'); el.addEventListener('suiFocus', () => { log.textContent = 'suiFocus'; }); el.addEventListener('suiBlur', () => { log.textContent = 'suiBlur'; }); el.addEventListener('suiInput', (e) => { log.textContent = `suiInput ${e.detail || '(empty)'}`; }); el.addEventListener('suiChange', (e) => { log.textContent = `suiChange ${e.detail || '(empty)'}`; }); }

Keyboard

KeyAction
TabMoves to the field and on to the next control; the host itself takes no tab stop.
Printable charactersType into the native input; suiInput fires on every keystroke.
EnterSubmits the surrounding form, as a native input does.

API

<sui-ifta-label>

Properties

PropertyAttributeTypeDefaultDescription
disableddisabledbooleanfalseDisables the field.
errorerrorstringstring | undefinedError message on the shared line under the box; paints the field in the danger tone and sets aria-invalid.
helphelpstringstring | undefinedHelp text on the shared line under the box. Replaced by error when set.
invalidinvalidbooleanfalseDanger border.
label*labelstringThe in-field label. It names the field; only without one does the host's aria-label or aria-labelledby, the rule every text field shares.
maxLengthmaxlengthnumbernumber | undefinedMaximum number of characters, as the native maxlength.
minLengthminlengthnumbernumber | undefinedNative minlength: a value shorter than this, once the user has typed, fails as tooShort.
namenamestringstring | undefinedForm control name. Reflected: form entry construction reads the content attribute, while all three framework bindings set properties, so an unreflected name posts nothing at all.
patternpatternstringstring | undefinedNative 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.
placeholderplaceholderstringstring | undefinedPlaceholder shown under the micro-label while the field is empty.
readOnlyreadonlybooleanfalseDisplay only: the text can be selected and copied but not edited; the field still posts its value.
requiredrequiredbooleanfalseMarks the field required (valueMissing validity when empty).
typetypeSuiInputType"email" | "password" | "search" | "tel" | "text" | "url"'text'Native input type. One union across the four elements that wrap a native text input.
valuevaluestring''Current value. Mutable; listen to suiInput / suiChange to observe edits.

Events

EventDetailReactVueDescription
suiBlurvoidonSuiBlur@sui-blurFires when the input loses focus; no detail. Does not bubble.
suiChangestringonSuiChange@sui-changeFires on commit (blur or Enter, native change); detail is the final value.
suiFocusvoidonSuiFocus@sui-focusFires when the input takes focus; no detail. The same pair is on every text field. Does not bubble.
suiInputstringonSuiInput@sui-inputFires on every keystroke; detail is the current value.

Methods

MethodSignatureDescription
select()select() => Promise<void>Selects the field text.
setFocus()setFocus() => Promise<void>Moves keyboard focus into the field.

Types

SuiInputType typeThe 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.

See also