v1.1.1

Form

Form layout patterns with labels, inputs, validation states, and helper text.

Login Form

Standard vertical form layout with email and password fields.

html
<form class="vt-w-full vt-max-w-sm vt-space-y-4" onsubmit="event.preventDefault()">
  <div class="vt-space-y-1.5">
    <label class="vt-label vt-block" for="form-1-1">Email</label>
    <div class="vt-relative">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-mail vt-absolute vt-left-3 vt-top-1/2 vt--translate-y-1/2 vt-w-4 vt-h-4 vt-text-foreground-muted">
        <path d="m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7"></path><rect x="2" y="4" width="20" height="16" rx="2"></rect>
      </svg>
      <input type="email" placeholder="you@example.com" class="vt-input vt-pl-10" id="form-1-1">
    </div>
  </div>
  <div class="vt-space-y-1.5">
    <label class="vt-label vt-block" for="form-1-2">Password</label>
    <div class="vt-relative">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-lock vt-absolute vt-left-3 vt-top-1/2 vt--translate-y-1/2 vt-w-4 vt-h-4 vt-text-foreground-muted">
        <rect width="18" height="11" x="3" y="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
      </svg>
      <input type="password" placeholder="Enter password" class="vt-input vt-pl-10" id="form-1-2">
    </div>
  </div>
  <button type="submit" class="vt-btn vt-btn-primary vt-w-full">Sign In</button>
</form>

With Helper Text

Form fields with hint text below the input.

html

Must be 3-20 characters, letters and numbers only

Maximum 160 characters

<div class="vt-w-full vt-max-w-sm vt-space-y-4">
  <div class="vt-space-y-1.5">
    <label class="vt-label vt-block" for="form-2-1">Username</label>
    <div class="vt-relative">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-user vt-absolute vt-left-3 vt-top-1/2 vt--translate-y-1/2 vt-w-4 vt-h-4 vt-text-foreground-muted">
        <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle>
      </svg>
      <input type="text" placeholder="johndoe" class="vt-input vt-pl-10" id="form-2-1" aria-describedby="form-2-3">
    </div>
    <p class="vt-text-xs vt-text-foreground-muted" id="form-2-3">Must be 3-20 characters, letters and numbers only</p>
  </div>
  <div class="vt-space-y-1.5">
    <label class="vt-label vt-block" for="form-2-2">Bio</label>
    <textarea rows="3" placeholder="Tell us about yourself..." class="vt-textarea vt-resize-none" id="form-2-2" aria-describedby="form-2-4"></textarea>
    <p class="vt-text-xs vt-text-foreground-muted" id="form-2-4">Maximum 160 characters</p>
  </div>
</div>

Validation States

Error and success states with colored borders and messages.

html

Please enter a valid email address

Username is available

<div class="vt-w-full vt-max-w-sm vt-space-y-5">
  <!-- Error state -->
  <div class="vt-space-y-1.5">
    <label class="vt-label vt-block" for="form-3-1">Email</label>
    <input type="email" value="not-an-email" class="vt-input vt-input-error" id="form-3-1" aria-invalid="true" aria-describedby="form-3-3">
    <p class="vt-text-xs vt-text-error-fill vt-flex vt-items-center vt-gap-1" id="form-3-3">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-circle-alert vt-w-3 vt-h-3">
        <circle cx="12" cy="12" r="10"></circle><line x1="12" x2="12" y1="8" y2="12"></line><line x1="12" x2="12.01" y1="16" y2="16"></line>
      </svg>
      Please enter a valid email address
    </p>
  </div>
  <!-- Success state -->
  <div class="vt-space-y-1.5">
    <label class="vt-label vt-block" for="form-3-2">Username</label>
    <input type="text" value="johndoe" class="vt-input vt-border-success-fill vt-focus-visible:ring-success-fill" id="form-3-2">
    <p class="vt-text-xs vt-text-success-fill vt-flex vt-items-center vt-gap-1">
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-check vt-w-3 vt-h-3">
        <path d="M20 6 9 17l-5-5"></path>
      </svg>
      Username is available
    </p>
  </div>
</div>

Horizontal Layout

Label and input on the same row for settings-style forms.

html
<div class="vt-w-full vt-max-w-lg vt-space-y-4">
  <div class="vt-flex vt-items-center vt-gap-4">
    <label class="vt-text-sm vt-font-medium vt-w-32 vt-shrink-0 vt-text-right" for="form-4-1">Full Name</label>
    <input type="text" value="John Doe" class="vt-input vt-flex-1" id="form-4-1">
  </div>
  <div class="vt-flex vt-items-center vt-gap-4">
    <label class="vt-text-sm vt-font-medium vt-w-32 vt-shrink-0 vt-text-right" for="form-4-2">Email</label>
    <input type="email" value="john@example.com" class="vt-input vt-flex-1" id="form-4-2">
  </div>
  <div class="vt-flex vt-items-center vt-gap-4">
    <label class="vt-text-sm vt-font-medium vt-w-32 vt-shrink-0 vt-text-right" for="form-4-3">Role</label>
    <select class="vt-input vt-flex-1 vt-appearance-none" id="form-4-3">
      <option>Developer</option>
      <option>Designer</option>
      <option>Manager</option>
    </select>
  </div>
  <div class="vt-flex vt-justify-end">
    <button type="button" class="vt-btn vt-btn-primary">Save Changes</button>
  </div>
</div>

Registration Form

Complete registration form with multiple field types.

Create Account

Fill in your details to get started

Use 8+ characters with a mix of letters and numbers

Guidelines

Form scaffolding: field stacks with labels, helpers and validation slots.

Do
Pair every field with a visible label above the input.
Don't
Don't use placeholder text as the only label.

Please enter a valid email address

Do
Show errors inline with an icon and a clear message.
Don't
Don't signal an error with color alone — add a message.

Anatomy

HTML structure of the Form component.

form                                         ← Form element
└── div.vt-space-y-1.5                           ← Field group
    ├── label                                    ← Field label
    ├── div.vt-relative                           ← Input wrapper (for icon)
    │   ├── svg                                  ← Leading icon (optional)
    │   └── input.vt-input                        ← Input field
    └── p.vt-field-description                    ← Helper / error message
└── button.vt-btn.vt-btn-primary                  ← Submit button

API Reference

All CSS classes available for the Form component.

Class Type Description
vt-space-y-4 Spacing Vertical spacing between form fields
vt-space-y-1.5 Spacing Tight spacing between label, input, and hint
vt-text-sm vt-font-medium Typography Form label text style
vt-h-10 vt-rounded-lg Shape Input height and border radius
vt-border vt-border-border-strong Border Default input border
vt-bg-surface-card Color Input background color
vt-focus-visible:ring-1 vt-focus-visible:ring-info-fill State Blue focus ring on input focus
vt-border-error-fill State Red border for error state inputs
vt-focus-visible:ring-error-fill State Red focus ring for error state
vt-border-success-fill State Green border for success state inputs
vt-text-error-fill Color Red text for error messages
vt-text-success-fill Color Green text for success messages
vt-text-foreground-muted Color Muted text for hint/helper text
vt-btn vt-btn-primary vt-w-full Component Full-width primary submit button
vt-checkbox Component Styled checkbox input

Accessibility

Keyboard and screen reader support.

Feature Details
Labels Every input must have a visible label linked via for/id attributes
Errors Error messages linked via aria-describedby, invalid fields use aria-invalid="true"
Required Required fields should use required attribute and aria-required="true"
Groups Related fields wrapped in fieldset with legend element
Submit Form submission feedback should be announced to screen readers