QuesoTextField
A text input field component that supports various input types, two-way data binding with v-model
, and provides a consistent interface for form inputs. All form field components share the same base structure for consistent styling and behavior across your application.
Basic Usage
vue
<template>
<queso-text-field
name="email"
label="Email Address"
placeholder="Enter your email"
type="email"
is-required
v-model="email"
/>
</template>
<script setup>
import { ref } from "vue";
import { QuesoTextField } from "@allomambo/queso";
const email = ref("");
</script>
Props
name
- Type:
string
- Required:
true
- Description: The name attribute for the input field.
label
- Type:
string
- Required:
false
- Description: The label text displayed above the input.
id
- Type:
string
- Required:
false
- Description: The ID attribute for the input field (defaults to
name
if not provided).
type
- Type:
"text" | "url" | "tel" | "email" | "number" | "date"
- Default:
"text"
- Description: The HTML input type.
placeholder
- Type:
string
- Required:
false
- Description: Placeholder text for the input field.
isRequired
- Type:
boolean
- Default:
false
- Description: Whether the field is required.
isDisabled
- Type:
boolean
- Default:
false
- Description: Whether the field is disabled.
isReadOnly
- Type:
boolean
- Default:
false
- Description: Whether the field is read-only.
isError
- Type:
boolean
- Default:
false
- Description: Whether the field has an error state.
extraAttributes
- Type:
Record<string, string>
- Required:
false
- Description: Additional HTML attributes to apply to the input element.
Slots
beforeLabel
- Props:
ExposedData
- Description: Content displayed before the label text.
label
- Props:
ExposedData
- Description: The main label content. Defaults to the
label
prop if not provided.
required
- Props:
ExposedData
- Description: Content displayed for the required indicator. Defaults to
*
if not provided.
afterLabel
- Props:
ExposedData
- Description: Content displayed after the label text.
beforeInput
- Props:
ExposedData
- Description: Content displayed before the input field.
beforeTextFieldInput
- Props:
{}
- Description: Content displayed before the text input element (inside the input wrapper).
afterTextFieldInput
- Props:
{}
- Description: Content displayed after the text input element (inside the input wrapper).
afterInput
- Props:
ExposedData
- Description: Content displayed after the input field.
error
- Props:
ExposedData
- Description: Content displayed when the field has an error state.
Examples
Basic TypeScript Support
vue
<template>
<queso-text-field
name="username"
label="Username"
placeholder="Enter your username"
v-model="username"
/>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { QuesoTextField } from "@allomambo/queso";
import type { QuesoTextFieldModel } from "@allomambo/queso";
const username = ref<QuesoTextFieldModel>("");
</script>
html
<div class="queso-field">
<label for="username" class="queso-field__label">
<span class="queso-field__label__text">Username</span>
</label>
<div class="queso-field__input">
<div class="queso-text-field">
<input
class="queso-text-field__input"
type="text"
id="username"
name="username"
placeholder="Enter your username"
/>
</div>
</div>
</div>
Email Field with Error Validation
vue
<template>
<queso-text-field
name="email"
label="Email Address"
type="email"
placeholder="Enter your email"
is-required
is-error
v-model="email"
>
<template #error>
<span>Please enter a valid email address</span>
</template>
</queso-text-field>
</template>
<script setup>
import { ref } from "vue";
import { QuesoTextField } from "@allomambo/queso";
const email = ref("");
</script>
html
<div class="queso-field is-error">
<label for="email" class="queso-field__label">
<span class="queso-field__label__text">Email Address</span>
<span class="queso-field__label__required">*</span>
</label>
<div class="queso-field__input">
<div class="queso-text-field">
<input
class="queso-text-field__input"
type="email"
id="email"
name="email"
placeholder="Enter your email"
required
/>
</div>
</div>
<div class="queso-field__error">
<span>Please enter a valid email address</span>
</div>
</div>
Custom Input with Icons
vue
<template>
<queso-text-field
name="search"
label="Search"
placeholder="Search for products..."
v-model="searchQuery"
>
<template #beforeTextFieldInput>
<span class="search-icon">🔍</span>
</template>
<template #afterTextFieldInput>
<button
v-if="searchQuery"
class="clear-button"
@click="clearSearch"
>
✕
</button>
</template>
</queso-text-field>
</template>
<script setup>
import { ref } from "vue";
import { QuesoTextField } from "@allomambo/queso";
const searchQuery = ref("");
const clearSearch = () => {
searchQuery.value = "";
};
</script>
html
<div class="queso-field">
<label for="search" class="queso-field__label">
<span class="queso-field__label__text">Search</span>
</label>
<div class="queso-field__input">
<div class="queso-text-field">
<span class="search-icon">🔍</span>
<input
class="queso-text-field__input"
type="text"
id="search"
name="search"
placeholder="Search for products..."
/>
<button class="clear-button">✕</button>
</div>
</div>
</div>
Read-only Field
vue
<template>
<queso-text-field
name="user-id"
label="User ID"
is-read-only
v-model="userId"
/>
</template>
<script setup>
import { ref } from "vue";
import { QuesoTextField } from "@allomambo/queso";
const userId = ref("USER-12345");
</script>
html
<div class="queso-field is-read-only">
<label for="user-id" class="queso-field__label">
<span class="queso-field__label__text">User ID</span>
</label>
<div class="queso-field__input">
<div class="queso-text-field">
<span class="queso-text-field__readonly">USER-12345</span>
</div>
</div>
</div>
With Extra Attributes
vue
<template>
<queso-text-field
name="search"
label="Search"
placeholder="Enter search term..."
:extra-attributes="{
'data-testid': 'search-input',
'aria-describedby': 'search-help',
autocomplete: 'off',
maxlength: '100',
}"
v-model="searchQuery"
/>
<div id="search-help" class="help-text">
Enter keywords to search for products
</div>
</template>
<script setup>
import { ref } from "vue";
import { QuesoTextField } from "@allomambo/queso";
const searchQuery = ref("");
</script>
html
<div class="queso-field">
<label for="search" class="queso-field__label">
<span class="queso-field__label__text">Search</span>
</label>
<div class="queso-field__input">
<div class="queso-text-field">
<input
class="queso-text-field__input"
type="text"
id="search"
name="search"
placeholder="Enter search term..."
data-testid="search-input"
aria-describedby="search-help"
autocomplete="off"
maxlength="100"
/>
</div>
</div>
</div>
<div id="search-help" class="help-text">
Enter keywords to search for products
</div>
Behavior
- Two-way Data Binding: Uses Vue 3's
defineModel
for seamlessv-model
integration - Form Integration: Designed to work seamlessly with HTML forms
- Input Types: Supports standard HTML input types:
text
,url
,tel
,email
,number
,date
- Read-only Mode: When
is-read-only
is true, displays the value as text instead of an input
Accessibility
- Label Association: Uses proper
label
element withfor
attribute - Required Indicator: Displays visual indicator for required fields
- Error States: Provides clear error messaging and styling
- Keyboard Navigation: Full keyboard accessibility support
- Screen Reader Support: Proper ARIA attributes and semantic structure
- State Management: Tracks hover and focus states for accessibility
CSS Classes
Field Container
.queso-field
- Main field container.queso-field.is-disabled
- Disabled state.queso-field.is-error
- Error state.queso-field.is-active
- Focused state.queso-field.is-hover
- Hover state.queso-field.is-read-only
- Read-only state
Label
.queso-field__label
- Label container.queso-field__label__text
- Label text.queso-field__label__required
- Required indicator
Input
.queso-field__input
- Input container.queso-text-field
- Text field wrapper.queso-text-field__input
- Input element.queso-text-field__readonly
- Read-only text display
Error
.queso-field__error
- Error message container
Type Declaration
typescript
export interface ExposedData {
fieldID: string;
fieldName: string;
isRequired: boolean;
isDisabled: boolean;
isReadOnly: boolean;
isError: boolean;
isActive: boolean;
isHover: boolean;
}
export type QuesoTextFieldType =
| "text"
| "url"
| "tel"
| "email"
| "number"
| "date";
export type QuesoTextFieldModel = string;
export interface QuesoTextFieldProps {
name: string;
label?: string;
id?: string;
type?: QuesoTextFieldType;
placeholder?: string;
isRequired?: boolean;
isDisabled?: boolean;
isReadOnly?: boolean;
isError?: boolean;
extraAttributes?: Record<string, string>;
}