Modern contact form
The card-on-a-gradient look, written out in full so you can see exactly which properties do the work. It is a shadow, a border radius, and a focus ring — every visual effect here is four or five lines of CSS, not a component library.
Replace YOUR_FORM_ID with a form of your own and this sends to your inbox.
<form class="card-form" action="https://submit.formpost.ai/YOUR_FORM_ID" method="POST">
<header>
<h2>Get in touch</h2>
<p>We usually reply within one working day.</p>
</header>
<div class="field">
<label for="name">Name</label>
<input id="name" type="text" name="name" required>
</div>
<div class="field">
<label for="email">Email</label>
<input id="email" type="email" name="email" required>
</div>
<div class="field">
<label for="message">How can we help?</label>
<textarea id="message" name="message" rows="4" required></textarea>
</div>
<button type="submit">Send message</button>
<p class="fine-print">We will only use your address to reply.</p>
</form>body {
margin: 0;
padding: 48px 16px;
background: linear-gradient(160deg, #eef2ff 0%, #fdf2f8 100%);
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
.card-form {
box-sizing: border-box;
width: 100%;
max-width: 440px;
margin: 0 auto;
padding: 32px;
background: #fff;
border: 1px solid rgba(15, 23, 42, 0.06);
border-radius: 20px;
box-shadow: 0 24px 48px -24px rgba(15, 23, 42, 0.25);
}
.card-form header {
margin-bottom: 24px;
}
.card-form h2 {
margin: 0;
font-size: 24px;
letter-spacing: -0.02em;
color: #0f172a;
}
.card-form header p {
margin: 6px 0 0;
font-size: 14px;
color: #64748b;
}
.field {
margin-bottom: 18px;
}
.field label {
display: block;
margin-bottom: 6px;
font-size: 13px;
font-weight: 600;
color: #334155;
}
.field input,
.field textarea {
box-sizing: border-box;
width: 100%;
padding: 12px 14px;
font: inherit;
color: #0f172a;
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 12px;
transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
}
.field input:focus,
.field textarea:focus {
background: #fff;
border-color: #6366f1;
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.15);
outline: none;
}
.field textarea {
resize: vertical;
}
.card-form button {
width: 100%;
padding: 13px 16px;
font: inherit;
font-weight: 600;
color: #fff;
background: linear-gradient(135deg, #6366f1, #a855f7);
border: 0;
border-radius: 12px;
cursor: pointer;
transition: filter 0.15s, transform 0.05s;
}
.card-form button:hover {
filter: brightness(1.08);
}
.card-form button:active {
transform: translateY(1px);
}
.fine-print {
margin: 14px 0 0;
font-size: 12px;
text-align: center;
color: #94a3b8;
}What actually makes it look modern
Three things, and none of them are the gradient. The shadow uses a negative spread and a large blur so it reads as ambient light rather than a drop shadow. The inputs sit on a slightly darker fill than the card, which separates them without a heavy border. And the focus state grows a soft ring instead of the browser default.
box-shadow: 0 24px 48px -24px rgba(15, 23, 42, 0.25);
background: #f8fafc;
border: 1px solid #e2e8f0;
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.15);The focus ring is not decoration
Anyone navigating by keyboard needs to see which field they are in. The rule here sets outline: none and immediately replaces it with a box-shadow ring plus a colour change — that is fine. Setting outline: none and stopping there is the single most common accessibility failure in styled forms.
Transitions worth having
The inputs transition border-colour, shadow and background together over 150ms. That is short enough to feel instant and long enough to be noticed. The button transitions brightness on hover and drops one pixel on :active, which is the cheapest way to make a button feel like a physical control.
Deliberately absent: any transition on layout properties. Animating width, height or padding on a form makes it feel unstable while somebody is trying to type into it.
Wiring it up
None of the styling changes how the form sends. Set the action to your endpoint and the modern contact form posts exactly like a plain one:
<form class="card-form" action="https://submit.formpost.ai/YOUR_FORM_ID" method="POST">Questions about this contact form
- Does this need Tailwind or a CSS framework?
- No. It is one stylesheet of ordinary CSS with no dependencies, no build step and no classes borrowed from anywhere. If you do use Tailwind, there is a version of this form written entirely in utility classes.
- Will the gradient button work in older browsers?
- linear-gradient has been supported everywhere for over a decade. The one modern property here is box-shadow with a negative spread, which is equally old. Nothing degrades badly — worst case a browser shows a flat colour.
- How do I match it to my brand?
- Change the two colours in the button gradient and the rgba value in the focus ring. Those three values are the entire palette; everything else is neutral slate and will sit under any accent colour.
- Can I make this contact form submit without reloading the page?
- Yes. Keep the markup exactly as it is and add a small submit handler that posts the FormData with fetch and an Accept: application/json header. The AJAX contact form example has the complete code.
Related examples
Simple contact form
Three fields, a button, and about forty lines of CSS. The one to start from.
Tailwind contact form
Utility classes only — no @apply, no component layer, no config changes.
AJAX contact form
Submit without a page reload and swap in a real confirmation.
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.