@fiscozen/input
v3.0.3
Published
Design System Input component
Keywords
Readme
@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/inputComponents
This package exports two components:
FzInput- Standard input with label, icons, and validation statesFzCurrencyInput- Specialized currency input with number formatting and validation
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. |
| 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
