Log in

Tailwind CSS contact form

Every style is a utility class on the element, so there is no stylesheet to add and nothing to configure. Paste it into any project that already has Tailwind and it looks like this immediately.

The rendered result. The code below is the source — it is not run inside this preview.

Replace YOUR_FORM_ID with a form of your own and this sends to your inbox.

Create your form
contact.html
<form
  action="https://submit.formpost.ai/YOUR_FORM_ID"
  method="POST"
  class="mx-auto flex max-w-md flex-col gap-4 rounded-2xl border border-slate-200 bg-white p-8 shadow-sm"
>
  <h2 class="text-xl font-semibold text-slate-900">Contact us</h2>

  <div class="flex flex-col gap-1.5">
    <label for="name" class="text-sm font-medium text-slate-700">Name</label>
    <input
      id="name"
      name="name"
      required
      class="rounded-lg border border-slate-300 px-3 py-2 text-slate-900 placeholder:text-slate-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/30"
    />
  </div>

  <div class="flex flex-col gap-1.5">
    <label for="email" class="text-sm font-medium text-slate-700">Email</label>
    <input
      id="email"
      type="email"
      name="email"
      required
      class="rounded-lg border border-slate-300 px-3 py-2 text-slate-900 placeholder:text-slate-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/30"
    />
  </div>

  <div class="flex flex-col gap-1.5">
    <label for="message" class="text-sm font-medium text-slate-700">Message</label>
    <textarea
      id="message"
      name="message"
      rows="4"
      required
      class="resize-y rounded-lg border border-slate-300 px-3 py-2 text-slate-900 placeholder:text-slate-400 focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/30"
    ></textarea>
  </div>

  <button
    type="submit"
    class="rounded-lg bg-indigo-600 px-4 py-2.5 font-medium text-white transition hover:bg-indigo-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
  >
    Send message
  </button>
</form>

Utilities, not @apply

It is tempting to collapse the repeated input classes into a .input rule with @apply. Resist it for a form this size: you have reinvented a component stylesheet, given up the ability to tweak one field in place, and the repetition you were avoiding was four lines. @apply starts paying off at the point where the same combination appears across several files.

The focus ring is three utilities

focus:border-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/30

focus:outline-none on its own would be an accessibility bug — it is only safe here because the ring utilities on the same element put the indicator back. On the button, prefer focus-visible: so a mouse click does not leave a ring behind.

Spacing with gap, not margins

The form is a flex column with gap-4, and each field is a flex column with gap-1.5. Nothing carries a margin, which means no collapsing margins, no last-child override, and adding or reordering a field never disturbs the spacing.

Version notes

  • This markup works on Tailwind v3 and v4 without changes. The utilities used have been stable across both.
  • Opacity shorthand (ring-indigo-500/30) needs v3 or newer. On older versions use ring-opacity-30.
  • You do not need the forms plugin. It normalises input appearance across browsers, which is useful — but every property it would set is set explicitly here.
  • If your build strips unused classes, make sure this file is inside your content globs, or the form will render unstyled.
The preview above is rendered with hand-written CSS that matches these utilities, so the page does not have to pull Tailwind from a CDN. The markup is what you copy.

Questions about this contact form

Do I need the Tailwind forms plugin?
No. The plugin normalises browser defaults, which is handy, but this markup sets every relevant property itself — border, padding, radius, focus ring. It renders identically with or without it.
Should I use @apply to shorten the repeated classes?
Not for one form. You would trade the ability to adjust a single field for a component stylesheet you now have to maintain. @apply pays off when the same combination is repeated across files.
Why is my form unstyled after building?
The file is outside your content globs, so the classes were purged. Add its path to the content array in your Tailwind config.
Does this work with Tailwind v4?
Yes, unchanged. Every utility used here behaves the same on v3 and v4, including the slash opacity syntax on the ring colour.

Related examples

Or go back to all 21 contact form examples.

Give this form an endpoint

Formpost takes the submission, emails it to you and keeps a searchable copy. Free for 250 messages a month, with unlimited forms and no card.