DEV Community

Cover image for A Keyboard Display using CSS Grid
Grant Sander
Grant Sander

Posted on

A Keyboard Display using CSS Grid

A Little Context

I'm certainly not an expert web developer/designer, so I get excited when I discover tools that make my life easier. At the moment, I'm excited about CSS grid. I have known about CSS grid for awhile, but I just now encountered a project that gave me a real idea as to why CSS grid is so great. I'd like to share a little bit about this experience.

I do online math curriculum development (and teach math) for a living, but I recently started doing freelance web development work (because I really enjoy learning about web dev.). I started working on a project for a client, that consists of creating web-based typing lessons. Part of the requirement was to create a non-interactive on-screen keyboard where the keys light up on keystroke.

This was going to be an interesting task, because the layout of keyboards is not very "rectangular," in the sense that keys are offset and some keys are wider or taller than others. Here's what I ended up with:

Keyboard preview

Bringing in "The Grid"

I noticed that 15 "normal sized" keys fit on a single row of the keyboard, but some rows contain a mixture of "wider" keys and "normal" keys. To handle this, I ended up splitting the keyboard container (the QWERTY keyboard, left side of image above) into 15*4 + 14 = 74 tiny little columns. Each "normal" key spans 4 of these columns, each gap between keys spans 1 column, and the wider keys span a variety of columns. Each row of the keyboard spans just 1 row, whose height is 4 times as large as the width of each column. This is shown here:

Keyboard grid

To do this, I had a grid container div#qwerty_container to place all of the keys, and then all of the keys are direct children of this container. The CSS (I'm using SASS) for this container is as follows:

$key_size: 32px

    display: grid
    grid-template-columns: repeat(74, $key_size/4)
    grid-template-rows: repeat(5, $key_size)
    grid-column-gap: 0px
    grid-row-gap: $key_size/4
Enter fullscreen mode Exit fullscreen mode

The display: grid indicates that this element has a grid layout. The grid-template-columns indicates the size of the columns, and I used the CSS repeat() function to save myself a lot of typing. Similarly, the grid-template-rows indicates the size of the rows.

Then, each child of this container is applied a class prefixed by .g- to indicate how many columns it should span. As an example, a normal key would have the class .g-4 and this class contains the following:

    grid-column: auto / span 4
Enter fullscreen mode Exit fullscreen mode

That's about all it takes! The grid-column: auto / span 4 indicates that this class shouldn't affect the starting column of the element, but the element should span 4 columns. I had my list of keys in a JS array, along with how many columns they should span, and then looped through this array and output the grid elements using Vue.JS. Pretty clean!

Why not Flexbox?

I'm not a CSS expert, but I think this could have been done using Flexbox, because I didn't really do anything "vertical" in nature. However, the number pad on the right side (see the first image) has keys that span multiple rows. Now, this is a place for the grid to really shine! I created the number pad in essentially the same way as the QWERTY keyboard. This is what the grid looks like for the number pad:

Number pad grid

However, the Plus and Enter keys both span two rows. Two handle that, I merely added an id to both of those keys and added a mere three extra lines of CSS for each of those keys. For example, say the Plus key has an id of numpad_plus. Then we could add the following to our SASS file:

    grid-row: auto / span 2
    height: 100%
    justify-content: center

Enter fullscreen mode Exit fullscreen mode

In this case, the grid-row: auto / span 2 indicates that this key should start at its "normal row," e.g. we aren't changing which row it starts at, but that the key should span 2 rows. Basically, this key should span two rows (along with the gap between the rows). The height: 100% and justify-content: center is just for the aesthetics of the keys.

... But is it Responsive?

The keyboard takes up a fair amount of horizontal space, so I wanted to make sure it looked good on narrower screens. CSS Grid actually made this pretty easy to implement. I picked a few breakpoints and added a media query at each. At each break point, I chose a "scale factor," such as 0.8, and essentially scaled everything relative to the grid by that scale factor - making the keyboard about 80% of its original size. Without a whole lot of extra work, I was able to nicely "shrink" the keyboard for smaller screens.


This certainly isn't a comprehensive guide on CSS grid (I recommend CSS Tricks' article for that), but for me, this was an enlightening experience and opened my eyes to the beauty of the grid. I thought I'd share this experience with others.

I'm also aware that I barely tapped into the potential of the grid - which is pretty exciting, because that means I have plenty more to learn and experience with the grid!

Top comments (6)

maxart2501 profile image
Massimo Artizzu

Too bad grid doesn't support non-rectangular areas 😝
You could've made a classic L-shaped enter key.

Anyway, that keyboard layout can be done in flex, but you have to create vertically oriented sub-containers, making everything a little complicated. Grid is so nice!

gksander profile image
Grant Sander

I thought about hacking together an L-shaped enter key by essentially combining a horizontal key and a vertical key, but I figured it'd look sketchy and the borders wouldn't look like they should.

Interesting - that's good to know! I originally did the QWERTY in flex, but figured doing the number pad in flex would be way more work. So I ended up doing both in grid.

I really like how these kinds of layouts can be done with so little markup. All of the elements are direct children of the container, so the HTML side of things just looks/feels way cleaner.

edlb profile image
Etienne de la Broïse • Edited

Great test case for trying CSS grid!
Following your article I made a few tweeks to have the QWERTY international keyboard (with an L-shaped enter key).
You can see the result here:

hryggrbyr profile image
Thomas Rigby

Good work, Grant! Do you have a link to this project online to see it in action? :)

gksander profile image
Grant Sander • Edited

Thanks, Thomas! You can check out a sample of it at (sorry, link died) (there's still some work to do for the project, but this is more or less the foundation of it). This is a "right hand, middle row" exercise.

vinicaval profile image
Vinicius Cavalcante Donato

nice post! Grid is amazing