Skip to content

Input

Enter a single line of text, a password or a number in the app’s local format, such as 1 234,50 or 1,234.50.

We send the receipt here.

<script setup lang="ts">import { ref } from 'vue'import { UiStack, UiField, UiInput } from 'grani' const value = ref('') const email = ref('') const address = ref(  'Office 4, 12 Long Harbour Street, Northfield Business Park, second floor, reception on the left',)</script> <template>  <UiStack class="w-full max-w-80">    <UiField label="Name">      <UiInput v-model="value" placeholder="Anna Petrova" />    </UiField>    <UiField      label="Email"      description="We send the receipt here."      :error="email.includes('@') || !email ? undefined : 'Enter an address with @'"      required    >      <UiInput v-model="email" type="email" autocomplete="email" />    </UiField>    <UiField label="Delivery address">      <UiInput v-model="address" />    </UiField>  </UiStack></template>

Also called text field, text input, number input, search field.

Usage

<UiInput v-model="value" />

With GraniResolver in the Vite config, a template needs no import: set it up once.

API

Name · typeDefaultDescription
Value
modelValue*string | nullThe value as text (v-model): empty is '', or null with numeric. A number is plain text (1234.5) parsed by its owner on use.
passwordVisiblebooleanWhether a password shows its characters (v-model:passwordVisible). Uncontrolled when omitted: the eye keeps the state.
State
loadingbooleanA request for this value is on its way, as a search: a spinner at the end in the cross's place, and clearing waits.
Behavior
typetext | search | email | password | url | telNative type, text by default. A number stays text with numeric: type="number" has its own spinner and rejects a comma.
inputmodenone | numeric | text | search | email | url | tel | decimalKeyboard to show on a phone.
maxlengthnumberMaximum number of characters.
numericbooleanA number as text: tabular monospaced digits, decimal keyboard, a comma becomes a point, and with an #end unit the value sizes to its content so the unit sits right after it.
stepnumberWith numeric: arrows in the capsule and ArrowUp/ArrowDown move the value by this much (0.1 for money, 1 for pieces). A value written more precisely moves by its own last digit.
minnumberWith numeric: the lowest value the arrows reach. Typing is not clamped: the form validates.
maxnumberWith numeric: the highest value the arrows reach.
Look
placeholderstringHint shown while empty. Not a replacement for a label.
sizexs | sm | mdStep of the control ladder. Unset, the app's size (createGrani({ size })), sm by default.
variantcapsule | barecapsule (the default) is the text field. bare has no capsule: the field is a window's header, edge to edge, larger type (a search over its results); the window draws the line under it. Text or search only, never numeric: no ring, no halo, size has no say.
Form and access
namestringNative name for forms.
idstringOwn id when standalone. Inside UiField the field's id takes precedence, so the label always points at the control.
autocompletestringBrowser autofill hint: email, current-password.
readonlybooleanPrevents editing while keeping the control focusable: something else sets the value.
disabledbooleanPrevents input and interaction.
invalidbooleanMarks the control invalid: red border and halo. Inside UiField the error sets this.
requiredbooleanStandalone only: a value is needed, said to a reader and to a form (native required). Inside UiField the field's required says so.
ariaLabelstringAccessible name when there is no visible label. A prop, not aria-label: the root is the capsule, the name belongs to the control.

Attributes: class and style stay on the outer element; the rest (native attributes, aria-*, data-testid) reach the control inside it.

When to use another component

When you needTake
Several linesTextarea
A pick from a listSelect
A dayDate picker
A count of things, with minus and plusStepper
A mark from 1 to NScale input
A new password with generate and copyPassword field
A one-time codeCode input