Tailwind Buttons and Forms

Buttons and forms are the two most interactive parts of any website. Buttons trigger actions. Forms collect data. Tailwind gives you the building blocks to style both beautifully without writing a single line of custom CSS.

Building Buttons with Tailwind

A Tailwind button is just a regular HTML <button> element with utility classes applied to it.

The Anatomy of a Button

<button class="bg-blue-600 text-white px-6 py-2 rounded font-semibold">
                   ↑            ↑       ↑     ↑       ↑
             Background     Text    Horizontal Vertical  Font
               color        color   padding  padding   weight

Basic Button

<button class="bg-blue-600 text-white px-6 py-2 rounded font-semibold">
  Click Me
</button>

Button Variants

Primary Button (filled)

<button class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded font-semibold transition">
  Save Changes
</button>

Secondary / Outlined Button

<button class="border-2 border-blue-600 text-blue-600 hover:bg-blue-600 hover:text-white px-6 py-2 rounded font-semibold transition">
  Cancel
</button>

Ghost Button (minimal)

<button class="text-blue-600 hover:underline px-4 py-2">
  Learn More
</button>

Danger Button

<button class="bg-red-500 hover:bg-red-600 text-white px-6 py-2 rounded font-semibold transition">
  Delete
</button>

Disabled Button

<button class="bg-gray-300 text-gray-500 px-6 py-2 rounded font-semibold cursor-not-allowed" disabled>
  Unavailable
</button>

Button Size Variants

Button Sizes Comparison:

[  XS  ]   [ Small ]   [  Medium  ]   [   Large   ]   [    XL     ]
  px-2       px-3          px-4           px-5           px-6
  py-1       py-1.5        py-2           py-2.5         py-3
 text-xs    text-sm      text-sm        text-base      text-lg
<button class="px-2 py-1 text-xs bg-blue-600 text-white rounded">XS</button>
<button class="px-3 py-1.5 text-sm bg-blue-600 text-white rounded">Small</button>
<button class="px-4 py-2 text-sm bg-blue-600 text-white rounded">Medium</button>
<button class="px-5 py-2.5 text-base bg-blue-600 text-white rounded">Large</button>
<button class="px-6 py-3 text-lg bg-blue-600 text-white rounded">XL</button>

Button with Icon

<button class="flex items-center gap-2 bg-green-600 text-white px-5 py-2 rounded">
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
    <path d="M5 13l4 4L19 7" stroke-width="2" stroke-linecap="round"></path>
  </svg>
  Approve
</button>

Full-Width Button

<button class="w-full bg-blue-600 text-white py-3 rounded-lg font-bold">
  Sign In
</button>

Rounded Pill Button

<button class="bg-purple-600 text-white px-8 py-2 rounded-full font-semibold">
  Subscribe
</button>

Button Groups

<div class="flex">
  <button class="bg-gray-200 text-gray-800 px-4 py-2 rounded-l border border-gray-300 hover:bg-gray-300">Left</button>
  <button class="bg-gray-200 text-gray-800 px-4 py-2 border-t border-b border-gray-300 hover:bg-gray-300">Center</button>
  <button class="bg-gray-200 text-gray-800 px-4 py-2 rounded-r border border-gray-300 hover:bg-gray-300">Right</button>
</div>
┌──────┬────────┬───────┐
│ Left │ Center │ Right │
└──────┴────────┴───────┘
  rounded              rounded
  left only            right only

Building Forms with Tailwind

Tailwind does not apply any default styles to form elements. You add every style intentionally. This gives you complete control.

The Basic Input Field Anatomy

<input class="w-full border border-gray-300 rounded p-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
                  ↑          ↑                 ↑      ↑          ↑                    ↑
              Full width   Border           Rounded Padding  Remove default          Blue ring
                                                             browser outline       on focus

Complete Contact Form

<form class="max-w-lg mx-auto p-6 bg-white rounded-xl shadow-md space-y-4">
  <h2 class="text-2xl font-bold text-gray-800">Contact Us</h2>

  <!-- Text Input -->
  <div>
    <label class="block text-sm font-medium text-gray-700 mb-1">Name</label>
    <input
      type="text"
      placeholder="John Doe"
      class="w-full border border-gray-300 rounded-lg p-2.5 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
    >
  </div>

  <!-- Email Input -->
  <div>
    <label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
    <input
      type="email"
      placeholder="john@example.com"
      class="w-full border border-gray-300 rounded-lg p-2.5 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
    >
  </div>

  <!-- Select Dropdown -->
  <div>
    <label class="block text-sm font-medium text-gray-700 mb-1">Topic</label>
    <select class="w-full border border-gray-300 rounded-lg p-2.5 bg-white focus:outline-none focus:ring-2 focus:ring-blue-500">
      <option>General Inquiry</option>
      <option>Support</option>
      <option>Billing</option>
    </select>
  </div>

  <!-- Textarea -->
  <div>
    <label class="block text-sm font-medium text-gray-700 mb-1">Message</label>
    <textarea
      rows="4"
      placeholder="Write your message..."
      class="w-full border border-gray-300 rounded-lg p-2.5 focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"
    ></textarea>
  </div>

  <!-- Checkbox -->
  <div class="flex items-center gap-2">
    <input type="checkbox" id="agree" class="w-4 h-4 text-blue-600 rounded">
    <label for="agree" class="text-sm text-gray-600">I agree to the terms</label>
  </div>

  <!-- Submit Button -->
  <button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2.5 rounded-lg font-semibold transition">
    Send Message
  </button>
</form>

Form Element Visual States

Normal State:         Focus State:           Error State:
┌──────────────┐      ┌──────────────┐       ┌──────────────┐
│  Enter name  │  →   │■ Typing...   │       │  John 123    │
└──────────────┘      └──────────────┘       └──────────────┘
border-gray-300      ring-2 ring-blue-500    border-red-500
                      border-transparent

                                             + ⚠ Invalid name format
                                               text-red-500 text-sm

Input with Validation Error Style

<div>
  <label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
  <input
    type="email"
    class="w-full border border-red-500 rounded-lg p-2.5 focus:outline-none focus:ring-2 focus:ring-red-400 bg-red-50"
    value="not-an-email"
  >
  <p class="mt-1 text-sm text-red-600">Please enter a valid email address.</p>
</div>

Input with Icon Inside

<div class="relative">
  <span class="absolute inset-y-0 left-3 flex items-center text-gray-400">🔍</span>
  <input
    type="text"
    placeholder="Search..."
    class="w-full border border-gray-300 rounded-lg py-2 pl-10 pr-4 focus:outline-none focus:ring-2 focus:ring-blue-500"
  >
</div>
┌─────────────────────────────┐
│ 🔍  Search...               │
└─────────────────────────────┘
  ↑
  absolute positioned icon (left-3)
  input has pl-10 to avoid overlap

Radio Button Group

<fieldset>
  <legend class="text-sm font-medium text-gray-700 mb-2">Choose a plan</legend>
  <div class="space-y-2">
    <label class="flex items-center gap-3 p-3 border rounded-lg cursor-pointer hover:bg-blue-50">
      <input type="radio" name="plan" value="free" class="text-blue-600">
      <span>Free Plan</span>
    </label>
    <label class="flex items-center gap-3 p-3 border rounded-lg cursor-pointer hover:bg-blue-50">
      <input type="radio" name="plan" value="pro" class="text-blue-600">
      <span>Pro Plan</span>
    </label>
  </div>
</fieldset>

Toggle Switch (Custom Checkbox)

<label class="flex items-center cursor-pointer gap-3">
  <div class="relative">
    <input type="checkbox" class="sr-only peer">
    <div class="w-11 h-6 bg-gray-300 rounded-full peer peer-checked:bg-blue-500 transition"></div>
    <div class="absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow transition peer-checked:translate-x-5"></div>
  </div>
  <span class="text-sm text-gray-700">Enable Notifications</span>
</label>
OFF:  [○         ]   ON:  [         ○]
       gray bg              blue bg
       circle left          circle right (translate-x-5)

Form Layout: Inline vs Stacked

Stacked (default / mobile-friendly):
┌─────────────────┐
│ Label           │
│ [_____________] │
│ Label           │
│ [_____________] │
└─────────────────┘

Inline (desktop search bar):
┌──────────────────────┬──────────┐
│  [________________]  │ [Search] │
└──────────────────────┴──────────┘
<!-- Inline form -->
<div class="flex gap-2">
  <input type="text" placeholder="Enter email..." class="flex-1 border rounded-l-lg p-2 focus:outline-none">
  <button class="bg-blue-600 text-white px-4 rounded-r-lg">Subscribe</button>
</div>

Summary

  • Use bg-*, text-*, px-*, py-*, rounded-* to build any button style
  • Use hover: and transition to add smooth interactive feedback
  • Use focus:ring-* and focus:outline-none together for accessible input focus styles
  • Use border-red-500 and error text for form validation states
  • Use relative + absolute positioning for icons inside inputs
  • Use sr-only and peer to build custom toggle switches

Leave a Comment