Skip to content

Split Contact Section with Form

Tailwind CSS contact section with a gradient info panel beside a validated contact form, topic chips, character counter and a simulated send state.

Live preview

Open in new tab

Code

A split contact section built with Tailwind CSS: a violet-to-fuchsia info panel with email, phone and office address sits next to a clean contact form with topic chips, a character counter, inline validation and a simulated send state. It suits contact pages, agency sites and the closing section of a product landing page.

How it works

The root is section.tcs-contact. Inside, one rounded card uses a five-column grid from the lg breakpoint: the info panel spans two columns and the form spans three. On phones the panel stacks above the form.

The panel uses bg-linear-to-br from-violet-700 via-violet-600 to-fuchsia-600 with two decorative circles. Contact details are a dl: each dt is an icon tile with a visually hidden label (Email, Phone, Office) and each dd holds a mailto: or tel: link or an address element. A small pill with a pinging dot shows the expected reply time.

The form is form.tcs-form with novalidate. Required fields sit in wrappers marked data-tcs-field, each with a hidden error message marked data-tcs-error. The topic chips are visually hidden radio inputs using the peer class; their sibling span turns violet with peer-checked: and shows a ring with peer-focus-visible:.

The script runs on DOMContentLoaded for every .tcs-form. On submit it checks each field (non-empty, checkValidity() for the email, checked for the consent box), sets aria-invalid, shows the error and adds its id to aria-describedby, then focuses the first invalid field. After the first attempt, fields re-validate on input, change and blur. The data-tcs-count element tracks the maxlength of the message. A valid submit disables .tcs-submit, reveals .tcs-spinner, waits for data-tcs-delay milliseconds, resets the form and writes a success message into data-tcs-status.

Customization

  • The window.setTimeout in the submit handler of script.js: replace it with fetch() to your endpoint; a commented example shows new FormData(form).
  • data-tcs-delay on .tcs-form: change the simulated send time (default 1200 ms).
  • maxlength="500" on #tcs-message: the counter reads the new limit automatically.
  • from-violet-700 via-violet-600 to-fuchsia-600 on the panel and bg-violet-600 on .tcs-submit: switch to another palette such as from-sky-700 to-cyan-500.
  • lg:grid-cols-5 with lg:col-span-2 and lg:col-span-3: give the form more or less room.
  • Add or rename topic chips by copying a label with a peer sr-only radio and changing its value.

Accessibility

Every input has a visible label, the chips are grouped in a fieldset with a legend, and radios stay keyboard operable with arrow keys. Errors are linked through aria-describedby only while they are visible, together with aria-invalid. The status line has role="status" and aria-live="polite", and the form sets aria-busy while sending. Contact icons are aria-hidden with sr-only labels. All controls show visible focus rings, and the spinner, ping and transitions stop under prefers-reduced-motion.

Usage notes

For several forms on one page, give each copy unique id values for inputs, errors and the counter.

Requirements

Add these to your page (already included in the download):

  • <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

The Tailwind browser build is for prototyping. In production, compile Tailwind with its CLI or your bundler.

Split Contact Section with Form – Tailwind CSS contact sections component screenshot
Split Contact Section with Form · Tailwind CSS Contact Sections

More Contact Sections

Contact Section with Details – Bootstrap 5 contact sections preview

Contact Section with Details

Bootstrap 5 contact section with address, phone and email cards, copy buttons and a CSS map placeholder with opening hours.