Input

Displays a form input with a floating label, clean states and slots for leading or trailing icons.

Installation

npx alixan-ui-nuxt add input

This command installs only the base Input component with built-in validation props.

Usage

The label moves when the input is focused or has a value. Use XControl for the value and validation state.

<script setup lang="ts">
import Input from '@/components/ui/input/Input.vue'

const control = useXControl('')
</script>

<template>
  <Input :control="control" label="Name" />
</template>

State

<script setup lang="ts">
import Input from '@/components/ui/input/Input.vue'

const readonlyControl = useXControl('readonly@example.com')
const disabledControl = useXControl('')
const errorControl = useXControl('')
</script>

<template>
  <div class="grid w-full gap-3">
    <Input :control="readonlyControl" label="Readonly" readonly />
    <Input :control="disabledControl" label="Disabled" disabled />
    <Input :control="errorControl" label="Required" error="Required field" />
 </div>
</template>

Validation

Parent invalid state: true
<script setup lang="ts">
import Button from '@/components/ui/button/Button.vue'
import Input from '@/components/ui/input/Input.vue'

const control = useXControl('')

const check = () => {
  control.validate()
}
</script>

<template>
  <Input :control="control" label="Username" required :min="3" :max="20" />
  <Button @click="check">{{ $t('inputValidation.check') }}</Button>
  <span>
    {{ $t('inputValidation.parentInvalid') }}: {{ control.invalid }}
  </span>
</template>

Length

6-12 characters

<script setup lang="ts">
import Input from '@/components/ui/input/Input.vue'

const control = useXControl('')
</script>

<template>
  <Input :control="control" label="Code" :min="6" :max="12" hint="6-12 characters" />
</template>

With Icon

<script setup lang="ts">
import { Eye, EyeOff, Lock, Mail } from '@lucide/vue'
import EmailInput from '@/components/ui/input/EmailInput.vue'
import IconButton from '@/components/ui/icon-button/IconButton.vue'
import Input from '@/components/ui/input/Input.vue'

const emailControl = useXControl('')
const passwordControl = useXControl('')
const isPasswordVisible = ref(false)
</script>

<template>
  <div class="grid w-full gap-3">
    <EmailInput :control="emailControl">
      <template #leading>
        <Mail class="size-5" />
      </template>
    </EmailInput>

    <Input
      :control="passwordControl"
      label="Password"
      :type="isPasswordVisible ? 'text' : 'password'"
    >
      <template #leading>
        <Lock class="size-5" />
      </template>
      <template #trailing>
        <IconButton
          variant="ghost"
          color="default"
          size="sm"
          @click="isPasswordVisible = !isPasswordVisible"
        >
          <EyeOff v-if="isPasswordVisible" />
          <Eye v-else />
        </IconButton>
      </template>
    </Input>
  </div>
</template>

Variants

Install focused wrappers when you want a dedicated component for a specific input pattern.

Username Input

npx alixan-ui-nuxt add username-input
<script setup lang="ts">
import UsernameInput from '@/components/ui/input/UsernameInput.vue'

const control = useXControl('')
</script>

<template>
  <UsernameInput :control="control" />
</template>

Email Input

npx alixan-ui-nuxt add email-input
<script setup lang="ts">
import EmailInput from '@/components/ui/input/EmailInput.vue'

const control = useXControl('')
</script>

<template>
  <EmailInput :control="control" required />
</template>

Password Input

npx alixan-ui-nuxt add password-input
<script setup lang="ts">
import PasswordInput from '@/components/ui/input/PasswordInput.vue'

const control = useXControl('')
</script>

<template>
  <PasswordInput
    :control="control"
    required
    :min="8"
    :max="32"
  />
</template>

Phone Input

npx alixan-ui-nuxt add phone-input

Default country code is +7. The input keeps it as a prefix and applies ### ### ## ## to the number.

<script setup lang="ts">
import PhoneInput from '@/components/ui/input/PhoneInput.vue'

const control = useXControl('')
</script>

<template>
  <PhoneInput
    :control="control"
    country-code="+7"
    placeholder="777 777 77 77"
  />
</template>

IIN

npx alixan-ui-nuxt add iin-input
<script setup lang="ts">
import IinInput from '@/components/ui/input/IinInput.vue'

const control = useXControl('')
</script>

<template>
  <IinInput :control="control" required />
</template>

API Reference

PropTypeDefaultDescription
controlXControl<string | number | null>-Optional XControl that owns the value, validation state and form interaction markers.
idstring-Custom id. Generated automatically when omitted.
labelstring-Floating label text.
type'text' | 'email' | 'password' | 'tel' | 'url' | 'number''text'Native input type.
placeholderstring-Native placeholder text.
autocomplete'on' | 'off'-Controls the native browser autocomplete behavior.
autofocusbooleanfalseFocuses the input on mount.
requiredbooleanfalseShows a localized required message after blur when the value is empty.
minnumber-Minimum text length validation shown after blur.
maxnumber-Maximum text length validation shown after blur.
patternstring-Native pattern string. The value must match the whole pattern after blur.
patternMessagestring'validation.pattern'Validation message shown when pattern does not match.
maskstring-Digit mask where # is a digit.
hintstring-Helper text shown below the input.
errorstring-Error message. Also switches the input into destructive state.
disabledbooleanfalseDisables input interaction.
readonlybooleanfalseMakes the input readable but not editable.
hasClearButtonbooleantrueShows a clear button when the input has a value and no trailing slot.

XControl API

PropTypeDefaultDescription
valueT-Current value owned by the control.
errorsRecord<string, string>{}Current validation errors keyed by required, min, max, pattern or external.
valid / invalidbooleantrue / falseDerived validity markers based on the current errors.
touched / untouchedbooleanfalse / trueTracks whether the user has left the field or validation was requested.
dirty / pristinebooleanfalse / trueTracks whether the value was changed through the field.
disabled / enabledbooleanfalse / trueDerived enabled and disabled state used by Input.
setValue(value)(value: T) => void-Updates the control value programmatically.
reset(value?)(value?: T) => void-Resets the value, errors and interaction markers.
validate()() => boolean-Marks the input as touched and returns whether it is valid.
hasError(key)(key: string) => boolean-Checks whether a particular validation error is active.
disable() / enable()() => void-Disables or enables the control and its Input.