input — Input
The input is the cornerstone of forms. core/input handles four things: display and computation of word counts, truncation of overlong input, inline styles per size tier, and the accessibility attribute bag for inputs. It deliberately does not touch validation (that is core/form’s job) or debouncing (that is the UI layer’s reactivity concern).
When to use
Section titled “When to use”- Each port implements
LhInput(including the textarea variant: the--textareamodifier class). - You need to reuse the same word-count and aria attributes on a custom input control.
- Should not use it: numeric input uses
core/input-number(has stepping and clamping), time usescore/time-picker, dates usecore/date-picker.
Import
Section titled “Import”import { getWordCount, shouldShowWordLimit, clampString, getInputStyle, getInputAria,} from '@lh-ui/share/core/input'import type { LhInputState } from '@lh-ui/share/core/input'Design intent
Section titled “Design intent”Both edges of getWordCount come from real cross-port differences:
- When
valueis undefined, the count falls back to 0 — React/uniapp controlled values may briefly be undefined before mount, andundefined.lengthwould blow up outright. - When
maxlengthis undefined, the limit shows∞instead of'undefined'. This symbol makes “no limit set” visually explicit rather than looking like a bug.
getInputStyle’s size styles are inline rather than class names: lh-ui inputs support global sizing via ConfigProvider, and switching the global size should not require recomputing classes — inline styles simply recompute from props. Note that the size mapping here differs from buttons (buttons use classes); this is the result of each component’s historical evolution.
Function table
Section titled “Function table”| Function | Signature | Returns | Purpose |
|---|---|---|---|
getWordCount |
(state: Pick<LhInputState, 'value' | 'maxlength'>) => string |
"used/limit" |
Word-count string |
shouldShowWordLimit |
(state: Pick<LhInputState, 'maxlength' | 'minlength'>) => boolean |
boolean | Show the count when maxlength or minlength is set |
clampString |
(value: string, maxlength?: number) => string |
string | Truncate overlong input |
getInputStyle |
(size: string) => Record<string, string> |
inline styles | Map padding/font-size per size tier |
getInputAria |
(options: { label?: string; describedby?: string; invalid?: boolean; required?: boolean }) => LhAriaAttrs |
aria attribute bag | Emits four attributes on demand |
getInputStyle tier mapping: mini padding 4px 8px / font-size 12, small 6px 10px / 12, medium 8px 12px / 14, large 12px 16px / 16; unknown sizes fall back to medium.
Type definitions
Section titled “Type definitions”export interface LhInputState { value: string size: LhComponentSize maxlength: number | undefined minlength: number | undefined}Accessibility
Section titled “Accessibility”The four attributes of getInputAria are all mounted on demand (emitted when truthy, key absent when falsy):
getInputAria({ label: 'Username', required: true })// { 'aria-label': 'Username', 'aria-required': true }
getInputAria({ invalid: true, describedby: 'lh-form-error-username' })// { 'aria-invalid': true, 'aria-describedby': 'lh-form-error-username' }The integration with core/form is the key usage: LhFormItem renders the error message element (the id is generated by getFormFieldErrorId(prop)) and passes that id in via describedby, so screen readers announce “invalid input, the error is…”. See form.
Usage examples
Section titled “Usage examples”import { getWordCount, clampString, getInputAria } from '@lh-ui/share/core/input'
getWordCount({ value: 'hello', maxlength: 10 }) // '5/10'getWordCount({ value: 'hello', maxlength: undefined }) // '5/∞'getWordCount({ value: undefined, maxlength: 10 }) // '0/10'clampString('abcdef', 3) // 'abc'clampString('abcdef') // 'abcdef' (no limit, returned as-is)getInputAria({ label: 'Search' }) // { 'aria-label': 'Search' }<!-- Vue3 --><div :class="['lh-input', `lh-input--${size}`, { 'lh-input--textarea': type === 'textarea' }]"> <div class="lh-input__wrapper"> <input class="lh-input__inner" :style="getInputStyle(size)" v-bind="getInputAria({ label, describedby, invalid: !!error, required })" /> </div> <span v-if="shouldShowWordLimit({ maxlength, minlength })" class="lh-input__count"> {{ getWordCount({ value, maxlength }) }} </span></div>// Reactconst aria = getInputAria({ label, describedby, invalid: !!error, required })return ( <div className={`lh-input lh-input--${size}`}> <div className="lh-input__wrapper"> <input className="lh-input__inner" style={getInputStyle(size)} {...aria} /> </div> </div>)// uniapp: <input> is a built-in component; both class and style bindings are supported;// textarea uses the <textarea> component, and on non-h5 targets word counting is handled// by the component's built-in count attributeStyles and tokens
Section titled “Styles and tokens”| Class | Semantics |
|---|---|
.lh-input |
Base class |
.lh-input--{mini|small|medium|large} |
Size tiers |
.lh-input--textarea |
textarea variant |
.lh-input--disabled / .lh-input--prefix / .lh-input--suffix |
States and slots |
.lh-input__wrapper |
Wrapper (border, focus state) |
.lh-input__wrapper--focused / --disabled / --has-label |
Wrapper states |
.lh-input__inner |
Native input element |
.lh-input__label / --float |
Floating label (material style) |
.lh-input__prefix / __suffix |
Prefix/suffix slots (icons, buttons) |
.lh-input__clear / __count |
Clear button / word count |
Focus border color uses var(--lh-primary-color), error state uses var(--lh-danger-color).
Caveats
Section titled “Caveats”- Asymmetric padding of
--has-label: with a floating label,padding-topis 16px (to leave room for the label); other tiers are symmetric. This is a pending-unification item recorded in the “control-height tokens” initiative. - Inconsistent control heights: input 37px / select 32px / cascader 27→32px, etc. The root cause is that
var.scsslacks--lh-control-height-*tokens (same as above, deferred to a later changeset). - The semantics of “characters” in
maxlength:clampStringusesslice, counting UTF-16 code units; emoji in the supplementary planes count as 2. If the UI layer needs code-point counting, handle it yourself. - Do not overwrite
sxwith the return value ofgetInputStyle— sx has higher precedence; the two should be merged, not overwrite each other.
@lh-ui/share/core/input → getWordCount( )(填好参数后点运行)Copyright © 2024-2026 FengMo WenXue