Text Input

Single-line text field with label, placeholder, helper text, icons, validation states, and character count.

Default

Standard input with a fieldset wrapper, legend label, and helper text below.

Full Name

Enter your legal name as it appears on your ID.

Email Address
<fieldset class="fieldset">
    <legend class="fieldset-legend">Full Name</legend>
    <input type="text" class="input w-full" placeholder="e.g. John Doe" />
    <p class="fieldset-label">Enter your legal name as it appears on your ID.</p>
</fieldset>

Sizes

Three size variants — input-sm, input-md (default), input-lg. Choose based on surrounding content density.

Small
Medium (default)
Large
<input type="text" class="input input-sm w-full" placeholder="Small" />
<input type="text" class="input input-md w-full" placeholder="Medium" />
<input type="text" class="input input-lg w-full" placeholder="Large" />

Floating Label

Label animates up when the field is focused or filled. Implemented with Alpine.js state + Tailwind transitions — no custom CSS needed.

<div class="relative"
     x-data="{ focused: false, filled: false }"
     @focusin="focused = true"
     @focusout="focused = false; filled = $el.querySelector('input').value.length > 0">
    <input
        type="text"
        class="input w-full pt-5 pb-1"
        @input="filled = $el.value.length > 0"
        placeholder=" "
    />
    <label class="absolute left-3 pointer-events-none transition-all duration-150 origin-left"
           :class="focused || filled
               ? 'top-1.5 text-[0.7rem] text-primary font-medium'
               : 'top-1/2 -translate-y-1/2 text-sm text-base-content/50'">
        Field label
    </label>
</div>

Prefix & Suffix Icons

Icons or addons inside the input using DaisyUI's label.input wrapper — no extra layout code required.

Search
Username
Website URL
Password
<!-- Prefix icon -->
<label class="input">
    <i data-lucide="search" class="w-4 h-4 opacity-50 shrink-0"></i>
    <input type="search" placeholder="Search…" />
</label>

<!-- Suffix icon -->
<label class="input">
    <input type="text" placeholder="yourhandle" />
    <i data-lucide="at-sign" class="w-4 h-4 opacity-50 shrink-0"></i>
</label>

<!-- Password toggle (Alpine.js) -->
<label class="input" x-data="{ show: false }">
    <input :type="show ? 'text' : 'password'" placeholder="••••••••" class="grow" />
    <button type="button" @click="show = !show">
        <i :data-lucide="show ? 'eye-off' : 'eye'" class="w-4 h-4"></i>
    </button>
</label>

Character Count

Live character counter with a configurable max. The counter turns red when the limit is exceeded — no custom CSS, just Tailwind conditional classes via Alpine.

Product Title

Limit exceeded Keep it short and descriptive

Meta Description

<fieldset class="fieldset" x-data="{ val: '', max: 50 }">
    <legend class="fieldset-legend">Product Title</legend>
    <input type="text"
           class="input w-full"
           :class="val.length > max ? 'input-error' : ''"
           x-model="val" />
    <p class="fieldset-label flex justify-between">
        <span>Keep it short and descriptive</span>
        <span :class="val.length > max ? 'text-error font-semibold' : 'text-base-content/50'"
              x-text="val.length + ' / ' + max"></span>
    </p>
</fieldset>

Validation States

Error and success states using DaisyUI modifier classes. Pair with fieldset-label for contextual feedback messages.

Email

Please enter a valid email address.

Username

Username is available.

Coupon Code

This code expires in 2 days.

<!-- Error -->
<fieldset class="fieldset">
    <legend class="fieldset-legend">Email</legend>
    <label class="input input-error w-full">
        <i data-lucide="alert-circle" class="w-4 h-4 text-error"></i>
        <input type="email" value="not-an-email" />
    </label>
    <p class="fieldset-label text-error">Please enter a valid email address.</p>
</fieldset>

<!-- Success -->
<fieldset class="fieldset">
    <legend class="fieldset-legend">Username</legend>
    <label class="input input-success w-full">
        <i data-lucide="check-circle" class="w-4 h-4 text-success"></i>
        <input type="text" value="john_doe" />
    </label>
    <p class="fieldset-label text-success">Username is available.</p>
</fieldset>

Readonly & Disabled

Use readonly when the value is displayable but not editable. Use disabled when the field is entirely inactive. Both reduce visual weight automatically via DaisyUI.

Order ID (readonly)

Cannot be changed after creation.

Promo Code (disabled)

Promotion has ended.

Empty readonly
Empty disabled
<!-- Readonly: value visible, not editable -->
<input type="text" class="input w-full" value="ORD-0042" readonly />

<!-- Disabled: full interaction blocked -->
<input type="text" class="input w-full" value="LAUNCH25" disabled />

Live Validation

Inline validation that runs on blur. State machine keeps feedback silent until the user has interacted — avoids premature error messages.

Email Address

We'll never share your email with anyone. Please enter a valid email address. Looks good!

<fieldset class="fieldset"
          x-data="{
              email: '',
              touched: false,
              get isValid() { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email); },
              get showError() { return this.touched && this.email.length > 0 && !this.isValid; },
              get showSuccess() { return this.touched && this.isValid; }
          }">
    <legend class="fieldset-legend">Email Address</legend>
    <label class="input w-full"
           :class="showError ? 'input-error' : showSuccess ? 'input-success' : ''">
        <input type="email"
               placeholder="you@example.com"
               x-model="email"
               @blur="touched = true"
               class="grow" />
        <i x-show="showSuccess" data-lucide="check" class="w-4 h-4 text-success"></i>
        <i x-show="showError" data-lucide="x" class="w-4 h-4 text-error"></i>
    </label>
    <p class="fieldset-label" :class="showError ? 'text-error' : showSuccess ? 'text-success' : ''">
        <span x-show="showError">Please enter a valid email address.</span>
        <span x-show="showSuccess">Looks good!</span>
    </p>
</fieldset>