Skip to content

Input ​

YueInput is a native single-line <input>: v-model, sizes, states, prefix/suffix content, and a real clear button. It does not own the label, helper text or error copy—that is YueField's job.

Every preview box has its own appearance toolbar in the top-right corner (light / dark / Accent / density / reset). It changes tokens, and every example on the page follows along.

Basic input and v-model ​

The value is always a string. The base input does not guess whether '42' is a number; conversion is the consumer's job, or a future typed field's.

BasicAll native input keyboard, IME and selection behaviour is preserved.

The value is:

Sizes ​

The three sizes reuse Button's control-size contract (ComponentSize) rather than the input inventing its own pixel values. When size is omitted it falls back to the app-level configuration.

Sizessm / md / lg, and falling back to configuration when size is omitted.
sizeHeightInline paddingFont sizePrefix/suffix icon
sm--input-height-sm--input-padding-inline-sm--input-font-size-sm--input-icon-size-sm
md--input-height-md--input-padding-inline-md--input-font-size-md--input-icon-size-md
lg--input-height-lg--input-padding-inline-lg--input-font-size-lg--input-icon-size-lg

disabled / readonly / invalid ​

These three are three different things, and they must look different too:

Three non-editable / invalid statesreadonly is not disabled; invalid is not disabled either.
StateNative behaviourVisual semantics
disabledNative disabled: not focusable, not submitted, screen readers do not treat it as editableDisabled background + disabled text + not-allowed cursor
readonlyNative readonly: still focusable, still selectable and copyable, still submittedQuieter background, text stays readable
invalidaria-invalid="true"Error boundary

The difference between readonly and disabled is not a matter of style

A readonly field exists for values that are "visible, selectable and copyable, but not editable"—an order number, say. Expressing that with disabled makes the value unselectable and uncopyable, and it is not submitted with the form either. Their contrast gates differ too: the disabled state is exempt under WCAG, the readonly state is not, so readonly text is still audited against 4.5:1.

invalid only says "validation failed", it does not explain why

It sets aria-invalid="true" and switches the error boundary, but it renders no error copy at all. Where the error is and how to announce it is YueField's business—if both components wrote their own error copy, there would be two sources of truth to keep in sync.

For focus priority in the invalid state, see the guide.

placeholder and native attributes ​

name, autocomplete, inputmode, required, maxlength, minlength, pattern, aria-* and id are all native attributes passed through, not Yue Props. They land on the real <input> inside, so label for, form submission, browser validation and autofill keep working as usual.

Native attributesThe label is associated with the inner input, not the outer div.

We use it to send the sign-in link and never make it public.

The table below shows which element each attribute ends up on—this is the component's public DOM contract:

AttributeLands onWhy
id, name, autocomplete, inputmode, required, maxlength, minlength, pattern, aria-*The inner <input>They are form-control semantics; putting them on a <div> is as good as not writing them
class, style, data-*The outer .yue-inputThey are the identity of "the whole component" and its test hooks

prefix / suffix ​

Slots, bound to no icon library. Mark decorative icons aria-hidden="true" yourself; do not put interactive controls inside a decorative span—when you need a button, use clearable or build your own separate control.

Prefix and suffix contentHeight, icon size and spacing all come from tokens.
CNY

Slots only add decoration: they do not change the value, the selection or keyboard behaviour, and they do not create extra focus targets.

clearable ​

The clear control is a real <button type="button">: it is reachable by Tab, it has an accessible name, and it has its own hover and focus-visible styles. After clearing, focus stays inside the input—clearing is the start of "typing again", not the end of editing.

ClearableAfter clearing, focus is still in the input; Tab reaches the clear button.

The clear control does not appear when the field is disabled, readonly or empty: offering "clear" on an input you cannot change is a lie.

Accessible name ​

The clear button's aria-label comes from Yue's locale catalog (key input.clear), English Clear by default. It is not a component Prop—one string per Prop serves one component only, has to be repeated at every call site, and turns "translating" into "editing markup".

One field, three locale sourcesThe three fields have identical markup: the first reads the page language (English), the second reads Chinese inside a locale subtree, and the third is given only a regional tag (zh-Hans-CN) for which no pack exists in the repository.

The three fields above have exactly the same markup; the only difference is which locale the outer LocaleScope switches the subtree to. The component does not know that "language" exists, it only reads t('input.clear'); verify:visual asserts three aria-label values in a real browser: the default reads the page language, the second equals '清空', and the third also equals '清空' — but that third one is the fallback chain at work: there is no zh-Hans-CN pack in the repository, so zh-Hans-CN falls back through zh-Hans-CN → zh-CN → zh → en-US to the Chinese pack instead of failing or rendering the key.

provideLocale() is exported from @yue-ui/vue/locale; the full contract is in the i18n guide.

Password ​

The first version only requires type="password" to pass through correctly. The plaintext toggle is the consumer's own suffix control—the base input does not secretly inject icons and internal state.

PasswordThe plaintext toggle is composed by the consumer, not built into the component.

Light / dark / Accent ​

All input colours come from tokens, so switching theme needs no JavaScript: --input-background, --input-border-color*, --input-color and --input-placeholder-color each resolve to different values in light and dark.

The same markup in three theme environmentsUse the switches at the top of the page to change theme and Accent; not one character of the markup below has to change.

In dark mode the Error boundary switches to a lighter red on a deeper ramp so it stays visible—these values are all inside the 110 gates of pnpm audit:tokens (including readonly text, focus boundary, error boundary, prefix/suffix text and the clear control). The assertions are not only at the token layer: verify:visual measures the real rendered result in the browser under all three environments—light, dark and a neutral Accent.

The component does not know the theme

There is not a single line of JS in YueInput that checks whether the current theme is light or dark, and there is no theme Prop. The theme is the result of token resolution, not component state—so server-side rendering does not produce different HTML for different themes.

State matrix ​

Theme × stateEvery cell is a real input; the light and dark contrast is measured in verify:visual.
resting
placeholder
disabled
readonly
invalid
readonly + invalid
clearable
prefix / suffix

Keyboard focus does not depend on colour

:focus-visible draws a focus ring around the whole field (--input-focus-ring-*) rather than just recolouring the border. When the invalid state is combined with focus, the error boundary keeps the error colour and the focus cue is carried by the ring—so keyboard users do not lose the "something is wrong here" information just because they focused the field.

Narrow screens ​

The field is 100% wide and allowed to shrink inside a flex / grid column (min-width: 0), so narrow screens only constrain it through the container and never push the page into horizontal scrolling.

Narrow widthNo horizontal overflow at a 390px viewport; this one is asserted in verify:visual.

RTL ​

dir belongs to the field itself rather than to the control inside it: the outer element is what lays out the prefix/suffix content. So dir lands on .yue-input and the inner <input> inherits it—the whole field mirrors together, instead of only the typed text mirroring while the prefix/suffix icons stay in their original order.

Right to leftThe prefix is rightmost and the clear button is on the left of the input.

Putting dir on an ancestor container works the same way: the inner <input> inherits the direction and the outer element remains the layout owner.

When not to use it ​

  • You need a label, helper text, error copy and a required marker → wait for YueField, do not push form layout back into the input;
  • You need multiple lines → YueTextarea, whose line height and resize differ from the single-line input;
  • You need number stepping, dates, dropdowns or tag input → separate components, rather than one type parameter covering everything;
  • You need number formatting → build a separate formatter first, and only then consider wiring it to an input.

Which "non-editable" state to choose ​

These three states are often mixed up, but their native behaviour is completely different:

Pick one of the threeFirst ask whether the user can still change it, then ask whether the value should still be submitted.
The question you are askingUse
The user entered something wrong and needs to retype itinvalid
The value comes from the system and the user can only view and copy itreadonly
This field simply does not apply right nowdisabled