Components

Input

Source
Collect single-line text with themed states, icons, avatars, and native keyboard events.
Install with the CLI
npx @vyui/cli add input

Overview

VyInput is the styled single-line input for Vue-Lynx. It combines the core native input with semantic colors, surface variants, sizes, loading state, leading or trailing content, and delayed autofocus.

Usage

The model accepts a string or number, but native edits are emitted as strings.

Input and return-key types

Use type to select the native software keyboard and confirmType to label its return key.

<VyInput
  v-model="query"
  type="text"
  confirm-type="search"
  leading-icon="i-lucide-search"
  placeholder="Search"
  @confirm="search"
/>

Available input types are text, number, digit, tel, email, and password. Available confirm types are done, next, search, send, and go.

digit requests a digits-only keyboard, while number requests the platform's numeric keyboard, which may include a decimal separator or sign. These are keyboard hints rather than application-level validation.

Icons, avatars, and loading

icon is leading by default. Set trailing to route the shorthand to the trailing side, or use the explicit icon props.

The loading spinner takes precedence over an avatar and leading icon. An explicit leadingIcon or trailingIcon takes precedence over the icon shorthand.

Icon names only resolve after their Iconify set has been registered. See Icon for setup.

Variants and validation emphasis

The semantic border and shadow ring paint automatically while the input is focused. Use highlight to force them on permanently, for example for validation emphasis.

highlight is visual only. It does not set an invalid state or provide an error message, so pair it with a visible label and validation text.

Disabled

Set disabled to prevent editing and apply the disabled visual treatment.

Custom leading and trailing content

The icon color is resolved to a Lynx-compatible hex value and passed to both named slots.

<VyInput v-model="amount" color="success" type="number" placeholder="0.00">
  <template #leading>
    <text class="text-neutral-500">$</text>
  </template>

  <template #trailing="{ iconColor }">
    <VyIcon name="i-lucide-circle-check" :color="iconColor" />
  </template>
</VyInput>

Clear action

Use the trailing slot for a one-tap clear action.

Copy action

Use the trailing slot for one-click copy actions. Keep the source text in state and pass that value to the clipboard handler instead of reading from the rendered input or slot content.

<script setup lang="ts">
import { ref } from 'vue'
import { VyButton, VyInput } from '@vyui/kit'

const value = ref('hello@vyui.dev')
const copied = ref(false)

async function copyValue() {
  const writeText = (globalThis as any).navigator?.clipboard?.writeText
  if (!writeText) return

  await writeText(value.value)
  copied.value = true

  setTimeout(() => {
    copied.value = false
  }, 1200)
}
</script>

<template>
  <VyInput v-model="value">
    <template #trailing>
      <VyButton
        size="xs"
        variant="ghost"
        color="neutral"
        :icon="copied ? 'i-lucide-check' : 'i-lucide-copy'"
        :label="copied ? 'Copied' : 'Copy'"
        @tap="copyValue"
      />
    </template>
  </VyInput>
</template>

The web clipboard API is shown here as an application-level handler. For native targets, wrap the platform clipboard bridge behind the same copyValue boundary.

Password toggle

Use a trailing button to switch the input between password and text.

Character count

Use the trailing slot for passive text such as a character count. VyInput does not currently expose the native maxLength prop, so enforce limits in your model handler when needed.

Phone country code

Combine VySelect with VyInput to build a phone field with country selection. VySelect is currently a sheet picker, not a searchable SelectMenu, so keep searchable or lazy-loaded country data in application code until that API exists.

Autofocus and imperative access

The kit wrapper exposes its core input instance through inputRef.

<script setup lang="ts">
import { VyButton, VyInput } from '@vyui/kit'
import { ref } from 'vue'

const input = ref<any>(null)
const value = ref('Editable text')

async function selectAll() {
  const core = input.value?.inputRef
  const current = await core?.getValue()
  await core?.focus()
  await core?.setSelectionRange(0, current?.value.length ?? 0)
}
</script>

<template>
  <VyInput
    ref="input"
    v-model="value"
    autofocus
    :autofocus-delay="150"
  />
  <VyButton @tap="selectAll">Select all</VyButton>
</template>

The core instance provides focus(), blur(), clear(), setValue(value), getValue(), and setSelectionRange(start, end), all returning promises.

Features and behavior

  • v-model sends programmatic changes to the native element without re-pushing every native keystroke.
  • type defaults to text; the underlying core input defaults confirmType to send.
  • The underlying core input applies its native maxLength default of 140; the kit wrapper does not currently expose a way to change it.
  • disabled blocks interaction and applies reduced opacity through the default theme.
  • loading adds a spinning leading icon but does not disable the input.
  • A custom leading slot, trailing slot, icon, avatar, or loading state creates the corresponding side region.
  • icon routes to the trailing side only when trailing is true; otherwise it is leading.
  • The leading boolean is present in the public props but does not currently change shorthand routing by itself.
  • The default slot is forwarded into the core native input; use named side slots for visual adornments.

Props

PropTypeDefaultDescription
modelValuestring | numberundefinedControlled value used by v-model; numbers are rendered as strings.
type'text' | 'number' | 'digit' | 'tel' | 'email' | 'password''text'Native input and software-keyboard mode.
confirmType'done' | 'next' | 'search' | 'send' | 'go'Core default 'send'Return-key label and behavior.
placeholderstringundefinedPlaceholder text.
disabledbooleanfalsePrevents user interaction.
loadingbooleanfalseShows the animated loading icon in the leading region.
loadingIconstringApp icon / i-lucide-loader-circleIconify name for the spinner.
iconstringundefinedLeading icon shorthand, or trailing when trailing is true.
leadingbooleanfalseDeclared shorthand hint; currently has no additional runtime effect.
trailingbooleanfalseRoutes icon to the trailing side.
leadingIconstringundefinedExplicit leading Iconify name; takes precedence over icon.
trailingIconstringundefinedExplicit trailing Iconify name; takes precedence over icon.
avatarAvatarPropsundefinedLeading avatar shown when not loading.
colorColor'primary'Semantic border, highlight, and icon color.
variant'outline' | 'soft' | 'subtle' | 'ghost' | 'none''outline'Surface treatment.
size'sm' | 'md' | 'lg' | 'xl''md'Padding, text, gap, and icon scale.
highlightbooleanfalseForces the semantic border and focus ring on permanently.
idstringundefinedNative identifier.
namestringundefinedNative field name.
requiredbooleanfalseNative required marker.
autocompletestring'off'Native autocomplete hint.
autofocusbooleanfalseFocuses the core input after mount.
autofocusDelaynumber0Delay before autofocus, in milliseconds.
classanyundefinedClasses merged onto the root wrapper.
uiPartial<Record<InputSlot, any>>undefinedPer-instance theme slot overrides.

Color defaults to primary, secondary, success, info, warning, error, or neutral, and supports consumer registry extensions.

The styled kit wrapper does not currently expose all core input props, including defaultValue, readonly, maxLength, inputFilter, and showSoftInputOnFocus. Because core defaults maxLength to 140, import Input from @vyui/core when you need a different limit, those other native controls, or the detailed input and selection events.

Emits

EventPayloadDescription
update:modelValuestringNative value changed; powers v-model.
confirmstringThe software keyboard's confirm action fired.
focusstringThe input received focus.
blurstringThe input lost focus.
keyboard{ visible: boolean, height: number, safeAreaBottom: number }Normalized software-keyboard visibility and dimensions.

The core primitive also emits detailed input(value, selectionStart, selectionEnd, isComposing) and selectionChange(selectionStart, selectionEnd) events, but the kit wrapper does not currently forward them.

Slots

SlotPropsDescription
leading{ iconColor: string }Replaces the loading icon, avatar, or leading icon.
trailing{ iconColor: string }Replaces the trailing icon.
defaultForwarded to the underlying core input primitive.

Exposed

PropertyTypeDescription
inputRefInputExposed | nullCore input instance containing the imperative methods.

setValue() changes the native value but does not itself emit update:modelValue. clear() emits an empty model value when the core input is controlled.

Styling and theming

Override globally through appConfig.ui.input or locally with ui.

import { createApp } from 'vue-lynx'
import { VyUI } from '@vyui/kit'
import App from './App.vue'

createApp(App)
  .use(VyUI, {
    ui: {
      input: {
        slots: {
          root: 'rounded-xl',
        },
        defaultVariants: {
          variant: 'soft',
          size: 'lg',
        },
      },
    },
  })
  .mount()
UI slotPurpose
rootSurface, border, radius, horizontal layout, padding, and gaps.
baseNative input, typed text, placeholder, and vertical padding.
leadingLeading adornment wrapper.
leadingIconLoading or leading icon.
leadingAvatarLeading avatar.
trailingTrailing adornment wrapper.
trailingIconTrailing icon.

The theme combines size, variant, color, highlight, and internal leading, trailing, and loading states. outline and subtle use semantic borders, while soft, ghost, and none reduce or remove the border treatment. While focused, or when highlight is set, the root paints a semantic border plus a shadow ring in the active color.

Because CSS inheritance is disabled in the Lynx build, typed-text and placeholder colors belong on base, while surface and border classes belong on root. The loading icon defaults to appConfig.ui.icons.loading; override that semantic icon globally or use loadingIcon per input.

Accessibility

Give every input a visible label. Use id with VyLabel where your form structure supports it, and keep instructions and validation text next to the field rather than relying on placeholder text, icons, or border color alone.

The core native input exposes the keyboard accessibility trait. disabled, required, type, and autocomplete are forwarded, but highlight, loading, icons, and avatars do not add an accessible description or invalid state. Give any interactive control placed in a side slot its own label and adequate tap target.

Use type="password" for secret text, but do not assume the keyboard type validates or sanitizes input. Autofocus can unexpectedly move focus and open the software keyboard, so reserve it for flows where immediate text entry is the user's clear next action.

Platform notes

  • The underlying control is Lynx's native <input>, with DOM fallbacks used by the core imperative methods in tests and web-compatible runtimes.
  • The normalized keyboard event comes from the focused native element and reports both keyboard height and safe-area bottom inset.
  • Use KeyboardAware wrappers when the software keyboard may cover the field. Inside a VyKeyboardAwareRoot, the input registers itself — no VyKeyboardAwareTrigger wrap needed.
  • Software-keyboard layouts, autocomplete behavior, password masking, and return-key labels can differ across iOS, Android, and web.
  • Focus is tracked in JS because Lynx has no :focus-within and the border and ring live on the root wrapper, not the native input; the ring itself is a flat box-shadow.
  • Leading and trailing elements are flex siblings rather than absolute overlays because Lynx does not reliably layer them over a native text input.
  • Lynx SVG does not inherit currentColor, so built-in and custom icon slots receive an explicit resolved hex color.
  • The default theme is light-mode-only.
  • Textarea for multi-line text.
  • KeyboardAware for avoiding the software keyboard.
  • FormField and Label for labels, help text, and validation messages.
  • Icon for registering and rendering Iconify icons.