DEV Community

Gohomewho
Gohomewho

Posted on

How to make a Gmail like checkbox

In this article, we will learn how to use HTML and CSS to make a Gmail like checkbox. But before we jump right into the topic, there are a few key concepts I want to cover first to make sure we are on the same page.

You can easily follow along by coding on Codepen. You can do that by clicking Start Coding button on the top left of Codepen home page.
Start Coding button snapshot


Basic

Here are a few things we need to know first to better understand how to make a Gmail like checkbox. You don't need to fully understand each thing below. Having a basic idea of them is good enough. And don't dive too deep yet when you are linked to the documents on MDN. It may be a lot easier than you think when we start building the checkbox.

Input elements

There is an element called input in HTML. We use it to collect information from users. There are many types of them.
For example:

<input type="text">
Enter fullscreen mode Exit fullscreen mode

The appearance of input might look different than yours based on the browser you are using, because browsers have their own default styles for input elements.
Make a <input type="text"> on Codepen

We can add some text to describe what information we want to collect from users. There is an attribute called placeholder that we can use on <input type="text"> element to provide a brief hint.

Name: <input type="text" placeholder="John Doe">
Enter fullscreen mode Exit fullscreen mode

The value of placeholder attribute will appear inside the input box.
add description and placeholder to input on Codepen

Pseudo-elements

A CSS pseudo-element is a keyword added to a selector that lets you style a specific part of the selected element(s).

we can style the input's placeholder like this

input::placeholder {
  color: blue;
}
Enter fullscreen mode Exit fullscreen mode

The text color of placeholder is set to blue.
add style to input::placeholder

Pseudo-classes

A CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s).

input:hover style input when input is hovered. input:hover::placeholder style input's placeholder when input is hovered.

input:hover::placeholder {
  color: red;
}
Enter fullscreen mode Exit fullscreen mode

We are styling the hover state, which requires a pointer to move on top of the element. Input's placeholder remains color: blue unless we move the pointer on top of it to trigger its hover state, then color: red will be applied.

hover on input

Positioned element

When we set position to a valid value other than static, the element we select becomes a positioned element.

Here is what will happen when we set position to absolute

The element is removed from the normal document flow, and no space is created for the element in the page layout. It is positioned relative to its closest positioned ancestor, if any; otherwise, it is placed relative to the initial containing block. Its final position is determined by the values of top, right, bottom, and left.

Normal flow is the default behavior how browsers place our elements. For example, the block elements are placed top to bottom and content(texts) are placed left to right.

<div>
  <div class="child">Hello</div>
  <div>World</div>
</div>
Enter fullscreen mode Exit fullscreen mode
.child {
  color: red;
}
Enter fullscreen mode Exit fullscreen mode

div by default is block element, so they are placed top to bottom. The texts inside of divs are placed left to right.
Show how two sibling div elements and the content are placed in document normal flow on Codepen

When we set div.child to position: absolute;, it no longer takes up space in the normal flow, as it doesn't exist.

.child {
  position: absolute;
}
Enter fullscreen mode Exit fullscreen mode

The div that has content "World" is now placed at where div.child would be. Because div.child is now taken out of flow, the "World" div will act like it should be placed first.
set .child to position absolute on Codepen

Containing block

We can control the position of a positioned element by defining top, right, left, and bottom. The offset will be relative to the element's closest containing block.

.child {
  position: absolute;
  right: 0;
}
Enter fullscreen mode Exit fullscreen mode

When we set right: 0;, as you can see, the .child div is now at the right edge of the document. The reason that .child is not positioned relative to .parent div is because if a positioned element does not have a positioned ancestor, its containing block will be the initial containing block, which has the dimensions of the viewport.

set right:0 on .child result to position at the right edge

we can make .parent div to be a positioned element so .child can be positioned relative to .parent div. Again, the value of position that is other than static can set a element to positioned element.

.parent {
  position: relative;
}
Enter fullscreen mode Exit fullscreen mode

.parent div is now a positioned ancestor of .child div. .parent div becomes the containing block of .child div, so setting top right left bottom on .child div will now be relative to .parent div
visual result on Codepen


How checkbox is made on Gmail?

Let's take a look at how checkbox looks like on Gmail and explore how it is made.

As you can see, when the pointer is close enough to the checkbox's bottom, left, top, except right, a circular clickable gray area will appear. That clickable gray area can toggle checkbox status.

interact Gmail checkbox

Inspect element with DevTools

DevTools allow us to do a bunch of stuff that help us develop. We can use it to inspect element on the screen. Press F12 to open DevTools panel(if F12 doesn't work for you, try google how to open DevTools panel)

Click the icon at the top left corner of DevTools panel then move our pointer to the element we want to inspect. We don't need to precisely click on the one we want. We can hover over elements to find which one we want.
the inspect icon on devtools panel

As shown in the image, it seems that the checkbox we are looking for is a div, and it has two pseudo elements ::before and ::after. When selecting ::before, we don't see it but it has a size 0*0, which means it is rendered. The div after ::before is set to display: none, so when selecting it, we don't see its size because browser doesn't render it. When selecting ::after, we can see its size covers the checkbox div.
inspect checkbox with devtools

Something you may have noticed is that the area of ::after seems to match the area that we could trigger the circular clickable area of checkbox.

We can change ::after size to confirm this.
change ::after in DevTools

Because pseudo-element is part of an element, it still belongs to that element. In this case, hovering on ::after is actually hovering on the checkbox div.

Next, we can explore where that circle comes from. We have learned that :hover style only applied when the :hover state is triggered. So we can select the elements one by one and see whose style changes on hover.
As we can see, the styles of checkbox div and ::before have :hover styles applied when hovering.
see which element styles change when hover

We can use DevTools to force element state rather than manually trigger a state. Force the checkbox div to be hover state so we can easily examine the styles applied by :hover. The circle we are looking for seems to be the ::before. Again, we can change its style to confirm that.

change checkbox's ::before style with DevTools

The circle comes from ::before has a initial size of 0*0, which is the result of setting transform: scale(0). When hover style applied, its size becomes 40*40, which is the result of setting transform: scale(1).

check ::before size with DevTools

Actually, We have gathered enough information to make a similar checkbox. We can use the native checkbox input element in HTML to build one. In order you are curious, the checkbox on Gmail is a fully custom checkbox. The checkbox div has a background image as the box. When the checkbox div is checked, the background image becomes a checked box.

demonstrate with DevTools


Let's start building

TODO:

  1. A checkbox
  2. A visible circular clickable area
  3. An invisible area that can make the circle appear
  4. Make it look nicer

A checkbox

First, we create a checkbox.

<input type="checkbox" class="gmail-checkbox" />
Enter fullscreen mode Exit fullscreen mode

That's all we need to do to have a functional checkbox.
create a checkbox on Codepen

A visible circular clickable area

Let's make a ::before equal to the checkbox size first. content: '' is necessary to create a ::before or ::after pseudo-element. position: absolute make it a positioned element , so we can set top right bottom left on it. inset: 0 is a shorthand as setting top: 0 right: 0 bottom: 0 left: 0 at once.

.gmail-checkbox::before {
  content: '';
  position: absolute;
  inset: 0;
  background-color: red;
  opacity: 0.5;
}
Enter fullscreen mode Exit fullscreen mode

I add background-color and opacity to illustrate a problem we have. The problem is that the ::before expand across the whole screen, because its containing block is the initial containing block which has the dimensions of the viewport.
::before expand across the whole screen

We want top right bottom left on ::before to be relative to the checkbox not the viewport. We need to make the checkbox a positioned element, so the containing block of ::before can be the checkbox instead of the initial containing block.

.gmail-checkbox {
  position: relative;
}
Enter fullscreen mode Exit fullscreen mode

Checkbox becomes the containing block of ::before.
::before has same size as checkbox visually

transform: scale(3) makes ::before larger and border-radius: 50% makes it rounded.

.gmail-checkbox::before {
  border-radius: 50%;
  transform: scale(3);
}
Enter fullscreen mode Exit fullscreen mode

Clicking on the red circle can toggle checkbox. We have learned that pseudo-element ::before is part of an element, so we are actually clicking on the checkbox.

click on ::before

We want to hide ::before the circle and only show it when hovering on the checkbox.

.gmail-checkbox::before {
  opacity: 0;
  transform: scale(0);
}

.gmail-checkbox:hover::before {
  transform: scale(3);
  opacity: 0.5;
}
Enter fullscreen mode Exit fullscreen mode

Currently, we have to hover exactly on the visible checkbox area to show ::before the clickable circle.

hover on checkbox to show ::before

An invisible area that can make the circle appear

We can make an invisible area as an extend of the checkbox to make it easier to be triggered hover state.

.gmail-checkbox::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: scale(3);
}
Enter fullscreen mode Exit fullscreen mode

I add background-color and opacity to illustrate the area of ::after. Hovering on ::after is actually hovering on the element it belongs to, so

hover on ::after

Make it look nicer

Add transition to the circle.

.gmail-checkbox:hover::before {
  transform: scale(3);
  opacity: 0.5;
  transition: transform opacity;
  transition-duration: 0.3s;
}
Enter fullscreen mode Exit fullscreen mode

transition effect on ::before

You may notice the color on ::before is coving the checkbox. That's because it is stacked on top of the checkbox. We can use z-index on positioned elements to control how elements are overlapped, but it is out of scope of this tutorial so we won't discuss it.

In our case, the color from ::before should be light , otherwise the checkbox won't be visible. We can use accent-color to change checkbox color.

Final result

final result

HTML

<input type="checkbox" class="gmail-checkbox" />
Enter fullscreen mode Exit fullscreen mode

CSS

.gmail-checkbox {
  position: relative;
  accent-color: red;
}

.gmail-checkbox::before {
  content: '';
  position: absolute;
  inset: 0;
  background-color: red;
  opacity: 0;
  transform: scale(0);
  border-radius: 50%;
} 

.gmail-checkbox:hover::before {
  transform: scale(3);
  opacity: 0.1;
  transition: transform opacity;
  transition-duration: 0.3s;
}

.gmail-checkbox::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: scale(3);
}
Enter fullscreen mode Exit fullscreen mode

Wrap up

First, we look at a few CSS fundamentals. Then, we inspect the checkbox on Gmail to see how it is made. Finally, we make a similar checkbox with all the knowledge we learn so far.

This article is meant for the beginners so I tried my best to break things down and I repeated a few things purposely because these fundamentals are not easy to understand. After having an overall idea, you can look for the materials you want to learn more.

I hope you find this article useful and I am welcome for any feedback. Thank you :D

Top comments (0)