Skip to content

Input ​

WxInput — a single-line text field with v-model, affix slots, a clear button and validation states.

Clearable, with counter
12/60

Value: Landing page

Sizes
Prefix, suffix, validation state
@email
Disabled & readonly

Usage ​

vue
<script setup lang="ts">
import { ref } from 'vue'

const title = ref('')
</script>

<template>
  <wx-input v-model="title" placeholder="Title" clearable />
  <wx-input v-model="email" type="email" status="error" />
  <wx-input v-model="slug" show-count :maxlength="60">
    <template #prefix>/</template>
  </wx-input>
</template>

Placeholders ​

Hand a field tokens and it helps to type placeholders — [phone], [year], whatever the application replaces them with when it prints the text. The field replaces nothing itself: the value keeps the brackets exactly as typed.

Input — type [, or press the button

Value: Call us on [phone] — or [fax], which is not a placeholder

Textarea
Rich text
Inline rich text

Value: Open since [year]<span>.</span>

  • Typing [ opens a list of the placeholders, narrowed by the letters that follow, with each one's current value beside it. The arrows walk it, Enter or Tab writes [name] in place of what was typed, Escape closes it. A [ straight after another [ opens nothing: [[name]] is the way to print the brackets themselves.
  • The button in the field lists them all and inserts the one clicked at the caret, or over the selection.
  • Known placeholders already in the text are drawn as chips. The input cannot draw one, so a mirror over it draws the same letters in the same places while the input's own go transparent — the caret, the selection and input methods stay the input's. Unknown names and [[escaped]] ones stay text.
vue
<template>
  <wx-input
    v-model="title"
    :tokens="[
      { name: 'phone', value: '+1 555 0100' },
      { name: 'year', value: '2026' },
    ]"
    tokens-title="Shortcodes"
    tokens-label="Insert a shortcode"
  />
</template>

WxTextarea and WxRichText take the same three props.

A placeholder that is nothing without its arguments brings them along: text is the whole bracket a row writes, and several rows may share a name, so a list can offer one row per thing to print: { name: 'gallery', text: '[gallery key=summer]', description: 'Summer' }.

Props ​

PropTypeDefaultDescription
modelValuestring | number | undefined''v-model value
type'text' | 'password' | 'email' | 'number' | 'search' | 'tel' | 'url''text'Native input type
size'sm' | 'md' | 'lg''md'Control height and font size
status'default' | 'success' | 'warning' | 'error''default'Validation state
placeholderstring—Placeholder text
disabledbooleanfalseDisables the field
readonlybooleanfalseRead-only field
clearablebooleanfalseShows a clear button when filled
maxlengthnumber—Native maxlength
showCountbooleanfalseRenders current / max (needs maxlength)
autocompletestring—Native autocomplete
idstringgeneratedOverrides the id the label points at; WxFormItem supplies one
ariaLabelstring—Label when there is no visible <label>
tokensTokenOption[]—Placeholders to suggest on [, list from the button and draw as chips
tokensTitlestring'Placeholders'Heading of the list the button opens
tokensLabelstring'Insert a placeholder'Name and tooltip of the button

Unknown attributes (name, id, required, …) fall through to the inner <input>, not the wrapper — with two exceptions. class and style stay on the wrapper, because that is the thing the caller can see: class="w-60" on a <wx-input> is asking for a narrower input, and a class that landed on the element inside it could not be reached from a parent's scoped CSS anyway.

Events ​

EventPayloadFires
update:modelValuestringOn every keystroke, and on clear
inputstringOn every keystroke, and on clear
changestringOn the native change event
focusFocusEventOn focus
blurFocusEventOn blur
clear—When the clear button is pressed

Slots ​

SlotDescription
prefixContent before the input (icon, @)
suffixContent after the input

Exposed methods ​

focus(), blur(), select(), and input — a ref to the native element.

vue
<script setup lang="ts">
const field = ref()
onMounted(() => field.value?.focus())
</script>

<template>
  <wx-input ref="field" />
</template>

Accessibility ​

  • status="error" sets aria-invalid="true" on the input.
  • The clear button is tabindex="-1" with aria-label="Clear", so it never gets in the way of keyboard navigation; focus returns to the input after clearing.
  • Use ariaLabel when the field has no visible label.

Released under the MIT License.