@fiscozen/input
Flexible input component library for Vue 3 applications, featuring icon support, validation states, multiple variants, and specialized currency input with number formatting.
Features
- Multiple Input Types: text, password, email, number, tel, url
- Icon Support: Left and right icons (static or clickable buttons)
- Validation States: Error and valid states with visual feedback
- Two Variants: Normal and floating-label presentation
- Two Environments: frontoffice and backoffice (different heights and styling)
- Currency Input: Specialized component with locale-aware number formatting
- Full Accessibility: ARIA attributes, keyboard navigation, screen reader support
- Customizable: Slots for label, icons, help text, and error messages
- TypeScript: Full type safety with TypeScript definitions
Installation
npm install @fiscozen/input
Components
This package exports three components:
FzInput- Standard input with label, icons, and validation statesFzCurrencyInput- Specialized currency input with number formatting and validationFzInputLabel- The label row of FzInput, with the required asterisk,truncateand anasidetext on the right; FzSelect renders it too. Use it directly only to build a field of your own
Basic Usage
FzInput
<script setup lang="ts">
import { FzInput } from '@fiscozen/input'
import { ref } from 'vue'
const email = ref('')
</script>
<template>
<FzInput label="Email" type="email" v-model="email" />
</template>
FzCurrencyInput
<script setup lang="ts">
import { FzCurrencyInput } from '@fiscozen/input'
import { ref } from 'vue'
const amount = ref<number | undefined>(undefined)
</script>
<template>
<FzCurrencyInput label="Amount" v-model="amount" />
</template>
Props
FzInput Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | - | Text label displayed above the input field. Overridden by label slot if provided. |
truncateLabel | boolean | false | Keeps the label on one line, cut with an ellipsis when it is wider than the field; a cut label shows in full in a tooltip on hover and while the input has focus. The required asterisk stays visible past the cut. Has no effect on the label slot. |
labelAside | string | - | Short text shown on the right of the label row, in a smaller size, such as a computed value next to a value typed by hand. The input announces it as its description. With truncateLabel the label is cut first, down to about twelve characters, and only then this text; without it, the label wraps and this text stays on its first line. Has no effect without label or on the label slot. |
environment | 'backoffice' | 'frontoffice' | 'frontoffice' | Environment determining input size and styling |
size | 'sm' | 'md' | 'lg' | - | Deprecated: Use environment prop instead. Size values map to environments: sm/md → backoffice, lg → frontoffice |
placeholder | string | - | Placeholder text shown when input is empty. Behavior differs based on variant. |
required | boolean | false | Marks input as required. Adds asterisk to label and sets native required attribute. |
disabled | boolean | false | Disables input interaction and applies disabled styling |
error | boolean | false | Shows error state with red border and enables errorMessage slot display |
valid | boolean | false | Shows success checkmark icon on the right when true. Takes precedence over rightIcon |
variant | 'normal' | 'floating-label' | 'normal' | Visual presentation style. 'floating-label' moves placeholder above input when focused/filled |
type | 'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | 'text' | Native HTML input type. Determines keyboard layout and validation behavior |
leftIcon | string | - | Font Awesome icon name displayed on the left side of input |
leftIconVariant | IconVariant | - | Visual style variant for left icon (solid, regular, light, etc.) |
leftIconButtonVariant | IconButtonVariant | - | Button variant for left icon when rendered as clickable button |
leftIconAriaLabel | string | - | Accessible label for left icon when clickable. Required for screen reader accessibility |
rightIcon | string | - | Font Awesome icon name displayed on the right side of input |
rightIconSize | IconSize | - | Deprecated: Size override for right icon. Icons now have a fixed size of "md". This prop is ignored. |
rightIconVariant | IconVariant | - | Visual style variant for right icon (solid, regular, light, etc.) |
rightIconButton | boolean | false | Renders right icon as clickable button instead of static icon |
rightIconButtonVariant | IconButtonVariant | 'invisible' | Button variant for right icon when rightIconButton is true |
rightIconAriaLabel | string | - | Accessible label for right icon when clickable. Required for screen reader accessibility |
secondRightIcon | string | - | Font Awesome icon name displayed as second icon on the right side of input. Order: secondRightIcon > rightIcon > valid (all can be present simultaneously) |
secondRightIconClass | string | - | Additional CSS classes applied to second right icon container |
secondRightIconVariant | IconVariant | - | Visual style variant for second right icon (solid, regular, light, etc.) |
secondRightIconButton | boolean | false | Renders second right icon as clickable button instead of static icon |
secondRightIconButtonVariant | IconButtonVariant | 'invisible' | Button variant for second right icon when secondRightIconButton is true |
secondRightIconAriaLabel | string | - | Accessible label for second right icon when clickable. Required for screen reader accessibility |
pattern | string | - | HTML5 pattern attribute for native browser validation |
name | string | - | Native name attribute for form submission and identification |
readonly | boolean | false | Native readonly attribute. Prevents user input while keeping field focusable |
maxlength | number | - | Native maxlength attribute. Limits maximum number of characters |
autocomplete | boolean | false | Native autocomplete attribute. Controls browser autocomplete and suggestions. When false, sets autocomplete="off" to disable browser autocomplete |
rightIconClass | string | - | Additional CSS classes applied to right icon container |
leftIconClass | string | - | Additional CSS classes applied to left icon container |
FzCurrencyInput Props
FzCurrencyInput extends FzInput props (except type, modelValue, rightIcon, rightIconSize, rightIconVariant, rightIconButton, rightIconButtonVariant, rightIconAriaLabel, rightIconClass, secondRightIcon, secondRightIconClass, secondRightIconVariant, secondRightIconButton, secondRightIconButtonVariant, secondRightIconAriaLabel) and adds:
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | number | string | undefined | - | Type assertion: Accepts number | string | undefined as input, but always emits number | undefined (never string). Strings are deprecated and trigger a console warning. See v-model Type Behavior for details. |
nullOnEmpty | boolean | false | Converts empty input to null instead of 0 |
minimumFractionDigits | number | 2 | Minimum decimal places in formatted output |
maximumFractionDigits | number | 2 | Maximum decimal places in formatted output |
min | number | - | Minimum allowed value. Values below this are clamped to min |
max | number | - | Maximum allowed value. Values above this are clamped to max |
step | number | 1 | Step increment for arrow buttons. When forceStep is true, values are rounded to nearest step multiple |
forceStep | boolean | false | Enforces quantization: values are automatically rounded to nearest step multiple |
stepUpAriaLabel | string | - | Custom accessible label for step up button. If not provided, uses default label |
stepDownAriaLabel | string | - | Custom accessible label for step down button. If not provided, uses default label |
Note: rightIcon and secondRightIcon props are not available in FzCurrencyInput. Only valid checkmark icon can be displayed alongside step controls.
Slots
| Slot | Description |
|---|---|
label | Custom label content (overrides label prop) |
left-icon | Custom left icon content (overrides leftIcon prop) |
right-icon | Custom right icon content (overrides rightIcon prop and valid checkmark) |
helpText | Help text displayed below input when no error is present |
errorMessage | Error message displayed below input when error is true |
Variants
Normal (Default)
Standard input with label above and placeholder inside the input field.
<FzInput label="Email" type="email" placeholder="Enter your email" v-model="email" />
Floating Label
Floating label variant moves placeholder above input when focused or when input has a value.
<FzInput
label="Email"
variant="floating-label"
placeholder="Enter your email"
v-model="email"
/>
Environments
Inputs support two environments that determine their height and styling:
- frontoffice (default): larger spacing
- backoffice: compact spacing
<template>
<FzInput label="Frontoffice (Default)" environment="frontoffice" v-model="value1" />
<FzInput label="Backoffice" environment="backoffice" v-model="value2" />
</template>
Note: The size prop is deprecated. Use environment instead.
Input Types
Text
<FzInput label="Name" type="text" v-model="name" />
Password
<FzInput label="Password" type="password" v-model="password" />
<FzInput label="Email" type="email" required v-model="email" />
Number
<FzInput label="Age" type="number" v-model="age" />
Telephone
<FzInput
label="Phone"
type="tel"
pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
v-model="phone"
/>
URL
<FzInput label="Website" type="url" v-model="website" />
States
Required
Required inputs show an asterisk (*) next to the label and set the native required attribute.
<FzInput label="Email" type="email" required v-model="email" />
Disabled
Disabled inputs prevent user interaction and apply muted styling.
<FzInput label="Disabled Input" disabled v-model="value" />
Error
Error state shows red border and displays error message via errorMessage slot.
<FzInput label="Email" type="email" :error="hasError" v-model="email">
<template #errorMessage>Please enter a valid email address</template>
</FzInput>
Valid
Valid state shows a green checkmark icon on the right side.
<FzInput label="Email" type="email" :valid="isValid" v-model="email" />
Readonly
Readonly inputs prevent editing but remain focusable and visible.
<FzInput label="Read-only Value" readonly v-model="readonlyValue" />
With Icons
Left Icon
<FzInput
label="Date"
leftIcon="calendar-lines"
v-model="date"
/>
Right Icon
<FzInput
label="Search"
rightIcon="magnifying-glass"
v-model="search"
/>
Right Icon as Button
Right icon can be rendered as a clickable button (useful for password visibility toggle, clear button, etc.).
<template>
<FzInput
label="Password"
:type="passwordType"
rightIcon="eye"
:rightIconButton="true"
rightIconButtonVariant="secondary"
rightIconAriaLabel="Toggle password visibility"
@fzinput:right-icon-click="togglePasswordVisibility"
v-model="password"
/>
</template>
<script setup>
import { ref } from 'vue'
const passwordType = ref('password')
const password = ref('')
const togglePasswordVisibility = () => {
passwordType.value = passwordType.value === 'password' ? 'text' : 'password'
}
</script>
Clickable Icons with Accessibility
When icons are clickable, provide leftIconAriaLabel or rightIconAriaLabel for keyboard accessibility:
<FzInput
label="Search"
leftIcon="magnifying-glass"
leftIconAriaLabel="Open search options"
@fzinput:left-icon-click="openSearchOptions"
v-model="search"
/>
Both Icons
<FzInput
label="Amount"
leftIcon="dollar-sign"
rightIcon="credit-card"
v-model="amount"
/>
Help Text and Error Messages
Help Text
Help text is displayed below the input when no error is present.
<FzInput label="Username" v-model="username">
<template #helpText>
Username must be between 3 and 20 characters
</template>
</FzInput>
Error Message
Error message is displayed below the input when error prop is true.
<FzInput label="Email" type="email" :error="hasError" v-model="email">
<template #errorMessage>
Please enter a valid email address
</template>
</FzInput>
Custom Label
You can provide custom label content using the label slot.
<FzInput v-model="value">
<template #label>
<strong>Custom Label</strong> with <em>formatting</em>
</template>
</FzInput>
Examples
Form with Validation
<template>
<form @submit.prevent="handleSubmit">
<FzInput
label="Email"
type="email"
required
:error="errors.email"
v-model="form.email"
>
<template #errorMessage v-if="errors.email">
{{ errors.email }}
</template>
</FzInput>
<FzInput
label="Password"
type="password"
required
:error="errors.password"
v-model="form.password"
>
<template #errorMessage v-if="errors.password">
{{ errors.password }}
</template>
</FzInput>
<button type="submit">Submit</button>
</form>
</template>
<script setup>
import { ref } from 'vue'
const form = ref({
email: '',
password: ''
})
const errors = ref({
email: null,
password: null
})
const handleSubmit = () => {
// Validation logic
}
</script>
Password with Visibility Toggle
<template>
<FzInput
label="Password"
:type="showPassword ? 'text' : 'password'"
rightIcon="eye"
:rightIconButton="true"
@fzinput:right-icon-click="togglePassword"
v-model="password"
/>
</template>
<script setup>
import { ref } from 'vue'
const password = ref('')
const showPassword = ref(false)
const togglePassword = () => {
showPassword.value = !showPassword.value
}
</script>
Search Input
<FzInput
label="Search"
leftIcon="magnifying-glass"
rightIcon="xmark"
:rightIconButton="true"
@fzinput:right-icon-click="clearSearch"
v-model="searchQuery"
/>
Input with Max Length
<FzInput
label="PIN"
type="text"
maxlength="4"
pattern="[0-9]{4}"
v-model="pin"
/>
FzCurrencyInput
Specialized currency input component built on FzInput with number formatting, validation, and step controls. Formats values using Intl.NumberFormat with locale-aware separators.
Features
- Locale-aware number formatting (decimal and thousand separators)
- Min/max value constraints
- Step quantization with arrow buttons
- Intelligent paste parsing (detects decimal/thousand separators automatically)
- Configurable decimal places
Basic Usage
<script setup lang="ts">
import { FzCurrencyInput } from '@fiscozen/input'
import { ref } from 'vue'
const amount = ref<number | undefined>(undefined)
</script>
<template>
<FzCurrencyInput
label="Amount"
v-model="amount"
:min="0"
:max="1000"
/>
</template>
With Step Controls
Step controls (arrow buttons) are always visible in FzCurrencyInput. Default step is 1, but can be customized.
<FzCurrencyInput
label="Quantity"
v-model="quantity"
:step="5"
/>
With Step Quantization
When forceStep is true, values are automatically rounded to the nearest step multiple.
<FzCurrencyInput
label="Quantity"
v-model="quantity"
:step="4"
:forceStep="true"
/>
With Min/Max Constraints
<FzCurrencyInput
label="Price"
v-model="price"
:min="0"
:max="9999.99"
:minimumFractionDigits="2"
:maximumFractionDigits="2"
/>
With Valid State
Valid checkmark icon is displayed alongside step controls.
<FzCurrencyInput
label="Amount"
v-model="amount"
:valid="isValid"
/>
Currency Input Behavior
- Formatting: Values are formatted using Intl.NumberFormat with locale settings (default: 'it-IT')
- Paste Handling: Automatically detects and parses various number formats (e.g., "1.234,56", "1,234.56")
- Step Controls: Arrow buttons are always visible (default step = 1). Support keyboard accessibility (Enter/Space to activate)
- Step Quantization: When
forceStepis true, values are automatically rounded to nearest step multiple - Empty Values: When
nullOnEmptyis true, empty input converts to null instead of 0 - Valid State: Valid checkmark icon can be displayed alongside step controls
- Right Icons:
rightIconandsecondRightIconprops are not available. Onlyvalidicon is supported.
v-model Type Behavior
FzCurrencyInput uses a type assertion pattern for its v-model:
- Accepts:
number | string | undefinedas input - Emits: Always
number | undefined(neverstring)
Type Assertion
The component accepts number | string | undefined as input, but always emits number | undefined. Strings are automatically parsed (Italian format: "1.234,56" → 1234.56) and converted to numbers internally.
Deprecation Warning
String values are deprecated and will be removed in a future version. A console warning is shown when strings are used. Please use number | undefined instead for type safety and future compatibility.
Recommended Usage
<script setup lang="ts">
import { ref } from 'vue'
// ✅ Recommended: number | undefined (future-proof)
const amount = ref<number | undefined>(undefined)
</script>
<template>
<FzCurrencyInput label="Amount" v-model="amount" />
</template>
Deprecated Usage (Still Works)
<script setup lang="ts">
import { ref } from 'vue'
// ⚠️ Deprecated: string (still works but shows warning)
// Strings are parsed and converted to numbers internally
const amount = ref<string>("1234,56")
</script>
<template>
<FzCurrencyInput label="Amount" v-model="amount" />
</template>
Note: When using strings, the component will:
- Show a console warning about deprecation
- Parse the string using Italian format (points = thousands, comma = decimal)
- Convert it to a number internally
- Always emit a
number | undefinedvalue
Migration Guide
If you're currently using strings, migrate to numbers:
<!-- Before (deprecated) -->
<script setup lang="ts">
const amount = ref<string>("1234,56")
</script>
<!-- After (recommended) -->
<script setup lang="ts">
const amount = ref<number | undefined>(1234.56)
// or
const amount = ref<number | undefined>(undefined)
</script>
Accessibility
FzInput and FzCurrencyInput are fully accessible and meet WCAG 2.1 AA standards:
- ARIA Attributes: Proper aria-required, aria-invalid, aria-disabled, aria-labelledby, aria-describedby
- Keyboard Navigation: Full keyboard support (Tab, Enter, Space, Arrow keys)
- Screen Readers: Error messages and help text are properly associated with inputs
- Focus Management: Visible focus indicators with proper contrast
- Semantic HTML: Native input elements with proper label associations
- Error Announcements: Error messages use role="alert" for immediate screen reader announcements
ARIA Attributes
- aria-required: Set to "true" or "false" (string values for Vue 3 compatibility)
- aria-invalid: Set to "true" when error prop is true
- aria-disabled: Set to "true" when disabled prop is true
- aria-labelledby: Links to label element when label prop is provided
- aria-describedby: Links to help text or error message when present
Error Message Accessibility
Error messages are rendered with role="alert" to ensure screen readers announce them immediately when displayed.
Behavior & Concepts
Label vs Slot Priority
When both label prop and label slot are provided, the slot takes precedence:
<FzInput label="This won't show">
<template #label>This will show instead</template>
</FzInput>
Right Icons Display Order
The component supports three types of right-side icons that can all be displayed simultaneously:
validcheckmark (whenvalidprop istrue) - displayed firstsecondRightIcon(when provided) - displayed secondrightIcon(when provided) - displayed third
All three icons can be visible at the same time, appearing in this order from left to right.
Floating Label Placeholder Behavior
In floating-label variant:
- When input is empty and not focused: placeholder shows above input as floating text
- When input has value or is focused: placeholder moves above input permanently
- Normal placeholder attribute is hidden in this mode
Icon Button Size Mapping
Right icon buttons use a smaller size scale than inputs to maintain visual balance:
- Input size
sm→ Icon button sizexs - Input size
md→ Icon button sizesm - Input size
lg→ Icon button sizemd
Notes
Input Type Behavior
Different input types provide different keyboard layouts and validation:
- email: Triggers email keyboard on mobile devices
- tel: Triggers numeric keyboard on mobile devices
- number: Allows numeric input with spinner controls
- password: Masks input characters
- url: Validates URL format
Currency Input Formatting
FzCurrencyInput uses Intl.NumberFormat for locale-aware formatting. The formatting respects:
- Browser locale settings
- Minimum and maximum fraction digits
- Decimal and thousand separator conventions
Paste Handling in Currency Input
The currency input uses intelligent heuristics to parse pasted values:
- Multiple different separators: rightmost is decimal separator
- Multiple same separators: thousand separator
- Single separator with <3 digits after: decimal separator
- Single separator with 3+ digits after: ambiguous, uses default formatting