Learn
🤖 AI Hub 📰 News 📖 Dictionary 🧰 Resources
Grow
💼 Jobs 🚀 Community 🏆 Challenges
Explore by Stage
🌑 Zero 📚 Learn 🔧 Practice 🏗 Build 🚀 Launch 💰 Earn
Account
Login Sign Up
🏗️HTML 🎨CSS ⚡JavaScript 🐙Git & GitHub ⚛️React Soon 📘TypeScript Soon 🐍Python 🗄️Database & SQL Soon 🌐Web Development Soon ☁️Cloud & DevOps Soon 🤖AI & ML Soon 📄Resume Prep Soon 🎤Interview Prep Soon 💼Freelancing Soon 🚀SaaS & Side Projects Soon 🤖Automation Soon
Intermediate 🕑 16 min read 👁 4 views 📅 Oct 21, 2026

Styling Forms: Inputs, Buttons and Focus States

Style HTML forms that are easy to use on any phone: consistent inputs, labels, focus states, accent-color, select boxes, buttons and friendly error states, for a coaching centre form.

A Form That Students Actually Finish

A coaching institute opens admissions for its JEE and NEET batches. Hundreds of students and parents will fill in the online registration form, most of them on a phone. If the boxes are tiny, the text is hard to read, and nobody can tell which box is selected, many people will give up halfway. A clean, clear form gets more registrations.

You already know how to build forms from the HTML Forms lesson. Without CSS, though, they use the browser’s default look, which is small, plain and slightly different in every browser. In this lesson you will style inputs, labels, dropdowns, checkboxes and buttons, add clear focus and error states, and build a mobile friendly registration form for Vidya Coaching Centre.

Step 1: Make Form Controls Use Your Font

Here is a surprise: inputs, buttons, selects and textareas do not inherit the page font. The browser gives them their own smaller font. The fix is one line, font: inherit, which you met in the Specificity and Cascade lesson:

<style>
  body { font-family: Georgia, serif; font-size: 18px; }
  .fixed input,
  .fixed button {
    font: inherit;
  }
</style>

<p>Browser defaults (small, different font):</p>
<input type="text" placeholder="Your name"> <button>Send</button>

<div class="fixed">
  <p>With font: inherit (same font as the page):</p>
  <input type="text" placeholder="Your name"> <button>Send</button>
</div>

Many developers put this at the top of every project, so that every form control matches the page text:

input, button, select, textarea { font: inherit; }

Step 2: Consistent Inputs with Labels Above

For most forms, the best layout is simple: the label sits above its field, and each field takes the full width. Labels above fields are easy to scan, they do not get squeezed on a phone, and they work well with long labels in any language.

Give every text field the same four things: font: inherit, comfortable padding, a clear border and a small border-radius. Add box-sizing: border-box so that width: 100% includes the padding and border, as you learned in the CSS Box Model lesson.

<style>
  body { font-family: system-ui, sans-serif; }
  .field { margin-bottom: 16px; max-width: 360px; }
  .field label {
    display: block;
    margin-bottom: 6px;
    font-weight: 600;
  }
  .field input,
  .field textarea {
    box-sizing: border-box;
    width: 100%;
    font: inherit;
    padding: 10px 12px;
    border: 1px solid #9ca3af;
    border-radius: 8px;
    background: white;
  }
  .hint { font-size: 14px; color: #4b5563; margin-top: 4px; }
</style>

<div class="field">
  <label for="name">Full name</label>
  <input id="name" type="text">
</div>
<div class="field">
  <label for="mail">Email</label>
  <input id="mail" type="email" placeholder="you@example.com">
  <p class="hint">We send your admit card to this address.</p>
</div>
<div class="field">
  <label for="msg">Any questions?</label>
  <textarea id="msg" rows="3"></textarea>
</div>

Notice the hint text under the email field. Short helper text like this prevents many mistakes. Keep the border colour dark enough to see clearly: a very light grey border may look stylish, but many users cannot tell where the box is.

Step 3: Clear Focus Styles

When a user clicks into a field or reaches it with the Tab key, the field has focus. Keyboard users depend on the focus style to know where they are, so never remove it without adding a better one. Two popular styles:

<style>
  body { font-family: system-ui, sans-serif; }
  input {
    font: inherit;
    padding: 10px 12px;
    border: 1px solid #9ca3af;
    border-radius: 8px;
    margin: 6px 0;
    transition: border-color 0.2s, box-shadow 0.2s;
  }
  .ring:focus {
    outline: 3px solid #2563eb;
    outline-offset: 2px;
  }
  .glow:focus {
    outline: 2px solid transparent;
    border-color: #7c3aed;
    box-shadow: 0 0 0 4px rgba(124, 58, 237, 0.3);
  }
</style>

<p>Click or Tab into each box:</p>
<input class="ring" placeholder="Outline style"><br>
<input class="glow" placeholder="Glow style">
  • The first uses outline with outline-offset, which leaves a small gap around the box.
  • The second changes the border colour and adds a soft “glow” with box-shadow. It also keeps a transparent outline, because in Windows high contrast mode shadows are hidden but outlines are shown.
:focus or :focus-visible? For buttons and links, use :focus-visible: it shows the focus style for keyboard users but not after every mouse click. For text inputs, browsers treat both the same way, because a user typing always needs to see where the cursor is.

Step 4: Checkboxes and Radios with accent-color

Checkboxes, radio buttons and range sliders used to be very hard to style. Now one property changes their colour: accent-color. Set it on the form or a parent, and every control inside uses your brand colour. You can also make them a bit bigger with width and height, which makes them easier to tap.

<style>
  body { font-family: system-ui, sans-serif; }
  .choices {
    accent-color: #ea580c;
  }
  .choices label { display: block; margin: 8px 0; }
  .choices input[type="checkbox"],
  .choices input[type="radio"] {
    width: 18px;
    height: 18px;
    vertical-align: middle;
  }
</style>

<fieldset class="choices">
  <legend>Batch timing</legend>
  <label><input type="radio" name="batch" checked> Morning (7 AM)</label>
  <label><input type="radio" name="batch"> Evening (6 PM)</label>
  <label><input type="checkbox" checked> Send me weekly test results</label>
  <label>Hours per day: <input type="range" min="1" max="8" value="3"></label>
</fieldset>

Wrapping each checkbox inside its <label> means a tap on the text also ticks the box. That gives phone users a much bigger target.

Step 5: Styling a Select Dropdown

A <select> takes the same padding, border and font as your inputs. The arrow is the tricky part. appearance: none removes the browser’s own arrow so the box looks the same everywhere, and then you draw your own. Here two tiny triangles made with linear-gradient form a down arrow on the right side:

<style>
  body { font-family: system-ui, sans-serif; }
  label { display: block; margin-bottom: 6px; font-weight: 600; }
  select {
    appearance: none;
    box-sizing: border-box;
    width: 100%;
    max-width: 320px;
    font: inherit;
    padding: 10px 40px 10px 12px;
    border: 1px solid #9ca3af;
    border-radius: 8px;
    background-color: white;
    /* two small triangles drawn with gradients form a down arrow */
    background-image:
      linear-gradient(45deg, transparent 50%, #374151 50%),
      linear-gradient(135deg, #374151 50%, transparent 50%);
    background-position:
      calc(100% - 20px) 50%,
      calc(100% - 14px) 50%;
    background-size: 6px 6px;
    background-repeat: no-repeat;
  }
  select:focus {
    outline: 3px solid #2563eb;
    outline-offset: 2px;
  }
</style>

<label for="course">Choose a course</label>
<select id="course">
  <option>JEE Main and Advanced</option>
  <option>NEET</option>
  <option>Class 10 Board Prep</option>
  <option>Spoken English</option>
</select>

The extra right padding (40px) keeps long course names from running under the arrow. The list of options that opens is still drawn by the browser or the phone, and that is fine: it is built to be easy to use on each device.

Step 6: Buttons: Primary, Secondary and Disabled

A form usually has one main action, like “Register”. Make that the primary button: solid colour, strong contrast. Other actions get a lighter secondary style, so the user knows which button matters most.

<style>
  body { font-family: system-ui, sans-serif; }
  .btn {
    font: inherit;
    font-weight: 600;
    padding: 10px 20px;
    border-radius: 8px;
    border: 2px solid #1d4ed8;
    cursor: pointer;
    margin: 4px;
    transition: background-color 0.2s, color 0.2s;
  }
  .btn-primary { background: #1d4ed8; color: white; }
  .btn-primary:hover { background: #1e40af; border-color: #1e40af; }
  .btn-secondary { background: white; color: #1d4ed8; }
  .btn-secondary:hover { background: #eff6ff; }
  .btn:focus-visible {
    outline: 3px solid #f59e0b;
    outline-offset: 2px;
  }
  .btn:disabled {
    background: #e5e7eb;
    border-color: #e5e7eb;
    color: #6b7280;
    cursor: not-allowed;
  }
</style>

<button class="btn btn-primary">Register</button>
<button class="btn btn-secondary">Download brochure</button>
<button class="btn btn-primary" disabled>Seats full</button>

The :disabled pseudo-class styles a button with the disabled attribute. Use grey colours and cursor: not-allowed so it clearly looks unavailable. Do not rely on colour alone: the text “Seats full” also explains why.

Step 7: Showing Errors with :user-invalid

HTML attributes like required, type="email" and pattern already know whether a value is valid, and CSS can read that. The older :invalid pseudo-class has a problem: an empty required field is invalid from the moment the page loads, so the form is covered in red before the user has typed anything.

The newer :user-invalid fixes this. It only matches after the user has changed the field and moved away, or tried to submit the form. Type a wrong email, then click outside the box:

<style>
  body { font-family: system-ui, sans-serif; }
  label { display: block; margin: 12px 0 6px; font-weight: 600; }
  input {
    box-sizing: border-box;
    width: 100%;
    max-width: 320px;
    font: inherit;
    padding: 10px 12px;
    border: 2px solid #9ca3af;
    border-radius: 8px;
  }
  input:user-invalid {
    border-color: #dc2626;
    background: #fef2f2;
  }
  input:user-valid {
    border-color: #16a34a;
  }
  .error {
    display: none;
    color: #b91c1c;
    font-size: 14px;
    margin-top: 4px;
  }
  input:user-invalid + .error {
    display: block;
  }
</style>

<form>
  <label for="email">Email</label>
  <input id="email" type="email" required placeholder="you@example.com">
  <p class="error">Please enter a valid email address.</p>

  <label for="pin">PIN code</label>
  <input id="pin" type="text" inputmode="numeric" pattern="[0-9]{6}" required>
  <p class="error">A PIN code has exactly 6 digits.</p>

  <p><button>Check</button></p>
</form>

The selector input:user-invalid + .error shows the message paragraph that comes right after an invalid input. :user-valid adds a green border when the value is correct. Current versions of Chrome, Edge, Firefox and Safari support these pseudo-classes. In an older browser the red borders simply do not appear, and the browser’s own messages still work when the form is submitted.

Real-Life Example: Vidya Coaching Centre Registration

Here is the complete registration form. It uses everything from this lesson. On a phone, every field is full width and the first and last name stack. From 520px wide, the two name fields sit side by side using a small grid. The input font size is 16px, because some phone browsers zoom into the page when you tap a field with smaller text.

<style>
  * { box-sizing: border-box; }
  body {
    margin: 0;
    padding: 16px;
    font-family: system-ui, sans-serif;
    background: #eef2ff;
    color: #1f2937;
  }
  .form-card {
    max-width: 480px;
    margin: 0 auto;
    padding: 24px;
    background: white;
    border-radius: 16px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
    accent-color: #4f46e5;
  }
  .form-card h2 { margin-top: 0; }
  .field { margin-bottom: 16px; }
  label, legend { display: block; margin-bottom: 6px; font-weight: 600; }
  input[type="text"], input[type="email"], input[type="tel"], select {
    width: 100%;
    font: inherit;
    font-size: 16px;
    padding: 12px;
    border: 1px solid #9ca3af;
    border-radius: 8px;
    background-color: white;
  }
  input:focus, select:focus {
    outline: 2px solid transparent;
    border-color: #4f46e5;
    box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.25);
  }
  input:user-invalid { border-color: #dc2626; }
  fieldset { border: none; padding: 0; margin: 0 0 16px; }
  .option { display: flex; align-items: center; gap: 8px; margin: 6px 0; font-weight: normal; }
  .row { display: grid; gap: 12px; }
  @media (min-width: 520px) {
    .row { grid-template-columns: 1fr 1fr; }
  }
  .submit {
    width: 100%;
    font: inherit;
    font-weight: 700;
    padding: 14px;
    border: none;
    border-radius: 8px;
    background: #4f46e5;
    color: white;
    cursor: pointer;
  }
  .submit:hover { background: #4338ca; }
  .submit:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }
</style>

<form class="form-card">
  <h2>Vidya Coaching Centre: Registration</h2>
  <div class="row">
    <div class="field">
      <label for="fname">First name</label>
      <input id="fname" type="text" required autocomplete="given-name">
    </div>
    <div class="field">
      <label for="lname">Last name</label>
      <input id="lname" type="text" autocomplete="family-name">
    </div>
  </div>
  <div class="field">
    <label for="email">Email</label>
    <input id="email" type="email" required placeholder="you@example.com">
  </div>
  <div class="field">
    <label for="course">Course</label>
    <select id="course" required>
      <option value="">Select a course</option>
      <option>JEE Main</option>
      <option>NEET</option>
      <option>Class 12 Commerce</option>
    </select>
  </div>
  <fieldset>
    <legend>Mode of classes</legend>
    <label class="option"><input type="radio" name="mode" checked> Classroom</label>
    <label class="option"><input type="radio" name="mode"> Online</label>
  </fieldset>
  <label class="option"><input type="checkbox" required> I agree to the fee and refund rules</label>
  <p><button class="submit">Register Now</button></p>
</form>

Try these changes:

  1. Change accent-color and the button colour to the coaching centre’s new colour, a dark green.
  2. Press Register Now with empty fields and watch the red borders and browser messages appear.
  3. Add a “Phone” field with type="tel" between Email and Course. It is already styled by the existing selector.

Common Mistakes

  • Inputs that stick out of their box. width: 100% plus padding and border is wider than the parent. Add box-sizing: border-box. See below.
  • Removing the outline with nothing in its place. outline: none on its own makes the form impossible to use with a keyboard. Always add a visible focus style.
  • Using a placeholder instead of a label. The placeholder disappears as soon as the user types, and its light colour is hard to read. Keep a real <label>.
  • Tiny tap targets. Small checkboxes and thin inputs are hard to use on a phone. Use enough padding, and make labels clickable.
  • Red borders before the user types. Styling :invalid shows errors on page load. Use :user-invalid.
<style>
  .box { width: 300px; padding: 10px; background: #fef3c7; }
  input {
    width: 100%;
    padding: 12px;
    border: 2px solid #374151;
  }
</style>

<div class="box">
  <input placeholder="Sticks out of the box">
</div>

Fixed with box-sizing: border-box:

<style>
  .box { width: 300px; padding: 10px; background: #fef3c7; }
  input {
    box-sizing: border-box;
    width: 100%;
    padding: 12px;
    border: 2px solid #374151;
  }
</style>

<div class="box">
  <input placeholder="Fits inside the box">
</div>

Practice Task: A Batch Enquiry Form

The coaching centre also wants a short enquiry form. The HTML is ready. Add the CSS by completing the TODO steps in the <style> block. Your finished form should have:

  • Bold labels above full width fields, with space between them.
  • Matching inputs and select with the page font, padding, border and rounded corners.
  • A clear green focus glow, a green checkbox and a full width green button.
  • A red border on fields the user filled in wrongly, but not on page load.
<form class="enquiry">
  <h2>Ask About Our Batches</h2>
  <label for="n">Your name</label>
  <input id="n" type="text" required>

  <label for="e">Email</label>
  <input id="e" type="email" required placeholder="you@example.com">

  <label for="c">Class</label>
  <select id="c">
    <option>Class 9</option>
    <option>Class 10</option>
    <option>Class 11</option>
    <option>Class 12</option>
  </select>

  <label><input type="checkbox"> Call me back</label>

  <button>Send Enquiry</button>
</form>

<style>
  body { font-family: system-ui, sans-serif; padding: 16px; }
  /* TODO 1: labels above the fields, bold, with space between fields */
  /* TODO 2: text inputs and select: full width, font: inherit, padding,
     border, rounded corners, and box-sizing: border-box */
  /* TODO 3: a clear focus style using box-shadow */
  /* TODO 4: green checkbox with accent-color */
  /* TODO 5: a full width green button with a hover colour */
  /* TODO 6: a red border for fields the user filled in wrongly */
</style>
Show one possible answer (try it yourself first!)
<form class="enquiry">
  <h2>Ask About Our Batches</h2>
  <label for="n">Your name</label>
  <input id="n" type="text" required>

  <label for="e">Email</label>
  <input id="e" type="email" required placeholder="you@example.com">

  <label for="c">Class</label>
  <select id="c">
    <option>Class 9</option>
    <option>Class 10</option>
    <option>Class 11</option>
    <option>Class 12</option>
  </select>

  <label><input type="checkbox"> Call me back</label>

  <button>Send Enquiry</button>
</form>

<style>
  body { font-family: system-ui, sans-serif; padding: 16px; }
  .enquiry { max-width: 420px; accent-color: #16a34a; }
  .enquiry label {
    display: block;
    margin: 14px 0 6px;
    font-weight: 600;
  }
  .enquiry input[type="text"],
  .enquiry input[type="email"],
  .enquiry select {
    box-sizing: border-box;
    width: 100%;
    font: inherit;
    padding: 10px 12px;
    border: 1px solid #9ca3af;
    border-radius: 8px;
    background: white;
  }
  .enquiry input:focus,
  .enquiry select:focus {
    outline: 2px solid transparent;
    border-color: #16a34a;
    box-shadow: 0 0 0 4px rgba(22, 163, 74, 0.25);
  }
  .enquiry input:user-invalid { border-color: #dc2626; }
  .enquiry button {
    width: 100%;
    margin-top: 18px;
    font: inherit;
    font-weight: 700;
    padding: 12px;
    border: none;
    border-radius: 8px;
    background: #16a34a;
    color: white;
    cursor: pointer;
  }
  .enquiry button:hover { background: #15803d; }
  .enquiry button:focus-visible { outline: 3px solid #f59e0b; outline-offset: 2px; }
</style>

Key Takeaways

  • Form controls do not inherit the page font. Add font: inherit to inputs, buttons, selects and textareas.
  • Put labels above full width fields, and use box-sizing: border-box with width: 100%.
  • Never remove focus styles. Use outline or a box-shadow glow, and :focus-visible for buttons.
  • accent-color colours checkboxes, radios and range sliders in one line.
  • Give the main action a strong primary button and style :disabled clearly.
  • Use :user-invalid to show errors only after the user has interacted with a field.

❓ Frequently Asked Questions

Each browser has its own default styles for form controls. Setting your own font, padding, border, border-radius and background removes most of the differences. For select boxes, appearance: none removes the rest.
accent-color is enough for most projects. For a completely custom design you can use appearance: none on the checkbox and draw it yourself, but you must then handle the checked and focus states carefully.
Some mobile browsers, especially Safari on iPhone, zoom in when an input's font size is smaller than 16px. Use a font size of 16px or more for inputs.
No. CSS only changes how fields look. The HTML attributes do basic checks in the browser, and the server must always check the data again, because users can bypass anything in the browser.
Was this lesson helpful?

🎯 Finished this lesson?

🔗 Related Tutorials
🤖 Got a Doubt? Ask AI
Get instant answers in Hindi or English
🤖
Z2T Bot
Online
Ask me anything about this tutorial — I'm here! 👋