DEV Community

Cover image for Semantic HTML-CSS Form
Manav Misra
Manav Misra

Posted on

Semantic HTML-CSS Form

Semantic HTML-CSS Form

We will create a simple 'user registration form' with semantic (using 'proper' tags in a right way) markup and with basic accessibility ♿ baked right in.

Getting Started

Starter Repo

I will be using my 'Front End Starter' repo. Here's a post I wrote about it:

For the rest of this post, I will assume that you are using this or something similar.


As per the TODOs shown in 'index.html,' we should add some type of Google Fonts

There's a link to a special CSS 💄 file from Google that belongs in our <head>. We also need to add the provided font-family rule to a body CSS selector.

Add Google Fonts

We should also replace the <title>. For Search Engine Optimization (SEO) purposes (not that that matters here - it's FYI), we should try to match up <title> with our <h1>.

<title>User Registration</title>
    <h1>User Registration</h1>
Enter fullscreen mode Exit fullscreen mode


HyperText Markup Language has one essential job - to describe the content on the page 📃. Each HTML 💬 tag should serve that purpose and nothing more!

Assuming that you are using VS Code (and you probably should be - it's damn near the industry-standard text editor for web dev!), you have 'built-in' access to something called 'Emmet.' It's a handy tool that saves us a lot of typing for HTML code.

Case and point, enter this: form>(div>label+input)*5+button
under the <h1> tag and press 'TAB' and 'RETURN' when you are finished.

If this doesn't work, you may have to hit ⬇️ to select the completion that says, 'Emmet Abbreviation', first.



Remove the action attribute from the opening <form - we don't need that spit!

Each for attribute inside of the label should corresponding with a matching id attribute in an input.

Add a placeholder attribute to each input to indicate what it's for.

The label is for accessibility ♿ purposes. We will use CSS to 'hide' it.

<label for="name">Name:</label><input type="text" placeholder="Name" id="name" required/>

Following this pattern 👆🏽, in addition to a 'name,' set up our form to take in: ✉️, ☎️, username and password.

While you're at it, add required to each input. This will simplify our lives by letting the browser confirm that the fields are filled in before the user can submit. Note that this is not usually sufficient by itself for a 'real' app. Additional client-side and/or server-side JS would be required as a 'backup.'

For, ✉️ and password, you should change the type attribute in those inputs from "text" to "email" and "password" respectively.

For ☎️, the type is: tel: <label for="fone">Phone</label><input type="tel" placeholder="Phone" id="fone" required/>

For the button - just put some text like, "Register Now!". <button>Register Now!</button>

Check ✅ Out How It Looks 👀 in the Browser

Go back to your terminal and do: npm start. This will fire up browser-sync - a local webserver with 'hot 🔥 reloading.'

It doesn't look 👀 gr8 - that's we need CSS 💄.


Let's also open this up on a simulated mobile screen by using Dev Tools. At least in Chrome, this is done on Mac with: 'COMMAN+OPTION+I' and then 'COMMAND+SHIFT+M'. From there, just pick one of the 📱 sizes - whatever you want.

Responsive Dev Tools

Let's establish a 'base font-size' by adding: font-size: 10px under the body selector. This will carry over to our relative CSS units for things like margin and padding later.

Get Rid of Labels

label {
  left: -9999px;
  position: absolute;
  top: -9999px;
Enter fullscreen mode Exit fullscreen mode

position: absolute takes the labels out of their normal 'positioning' and allows us to directly move them all really far off of the screen.


You might think 🤔 that we can just throw a text-align: center under body and be done. Although that would work here, we are trying to learn some better habits that will carry over to larger projects.

text-align should be used for aligning...text 😼. We'll align our elements with display: flex 👈🏽 That goes under body.

Having a look 👀 in our browser, we see that the h1 and the form are sort of 'side-by-side.'

By default, applying display: flex makes all of the direct children - of an element line up in a row. But, creating this 'parent-child' 'flex' relationship allows us to easily align things how we want to. Just put: flex-direction: column underneath body. Now, things are looking 👀 better.

Now, align-items: center; under body.

Now, let's get the button in the form centered.

form {
  align-items: center;
  display: flex;
  flex-direction: column;
Enter fullscreen mode Exit fullscreen mode


In fact, to avoid some of the rule duplications, consolidate:

form {
  align-items: center;
  display: flex;
  flex-direction: column;
Enter fullscreen mode Exit fullscreen mode


input {
  /* top/bottom left/right */
  margin: 4px 0;
Enter fullscreen mode Exit fullscreen mode


button {
  background-color: #48c774;
  border-color: transparent;
  border-radius: 4px;
  color: white;
  padding: 0.5rem;
Enter fullscreen mode Exit fullscreen mode

border-color: transparent is to get rid of that ugly default behavior.

I encourage you to tinker with these other values 👆🏽 and you'll soon see what they do.

There's still a lot more that could be done or course, but for the purposes of a form, this is styled well enough, for now.

Top comments (0)