Dylan Smith

Styling the kbd element

To oversimplify, the <kbd> HTML element represent keypresses. MDN explains it more thoroughly than I can.

The <kbd> HTML element represents a span of inline text denoting textual user input from a keyboard, voice input, or any other text entry device.

As a very basic example, you might write some code like this:

To copy text, highlight it and press <kbd></kbd> + <kbd>C</kbd>.

I like any HTML element that is semantically specific and unambiguous in its usage; <kbd> fits the bill perfectly. It’s such a meta HTML thing that it probably won’t surprise you to learn it was standardised in HTML 2.0 in 1995.

What I like most about <kbd>, though, is how well it lends itself to interesting visual styles. It usually represents a single key on a keyboard. Physical and virtual keys are little squares and rectangles. If all you do is add a border to it, you’re most of the way there. Even though I very rarely actually get to use this element on my site, I wanted to dress it up as a bit of an Easter egg.

To steal the code below, highlight it and press + C on Mac or Ctrl + C on Windows.

(Note this code uses some CSS custom properties specific to my codebase that might look a bit odd but are hopefully named in an understandable way.)

kbd {
  // Set up custom properties for colours so we can switch them in dark mode
  --kbd-color-background: var(--color-background-primary);
  // These interpolated variables reference a SCSS map of HSL-based greys
  --kbd-color-border:     #{color(grey, 80)};
  --kbd-color-text:       var(--color-text-primary);

  // In dark mode, a straight-up inversion doesn’t work for
  // the “physical” key look so they need to be adjusted
  @media (prefers-color-scheme: dark) {
    --kbd-color-background: #{color(grey, 55)};
    --kbd-color-border:     #{color(grey, 25)};
    --kbd-color-text:       #{color(grey, 14)};

  // Match the page defaults in light mode but
  // switch to a light-ish grey in dark mode
  background-color: var(--kbd-color-background);
  color: var(--kbd-color-text);

  // Round off the corners like physical keys have
  border-radius: 0.25rem;

  // Add a simple border
  border: 1px solid var(--kbd-color-border);

  // A sharp shadow (with no blur) really gives
  // the old school keyboard look
  box-shadow: 0 2px 0 1px var(--kbd-color-border);

  // Remove the text cursor — totally optional
  // but I wanted it for my hover effect
  cursor: default;

  // By default, browsers style <kbd> with a monospace typeface
  font-family: var(--font-family-sans-serif);

  // If we do all this with the default font size
  // (mine is 18px on desktop) it’ll look massive
  // and bump into lines above and below
  font-size: 0.75em;

  // Remove any extra space so I can accurately tweak the padding
  line-height: 1;

  // Make narrow numbers and letters look less odd
  min-width: 0.75rem;
  // `min-width` doesn’t work on inline elements
  display: block;
  // Keep the characters centred when narrower than the `max-width`
  text-align: center;

  // Seemed to look more key-like with more horizontal padding 🤷
  padding: 2px 5px;

  // These two lines pull the whole element up now that they’re
  // bottom-heavy due to the `box-shadow`. This looks better
  // against the cap height of regular paragraph text.
  position: relative;
  top: -1px;

  // This is my favourite part of the whole thing. The key gets
  // “pushed” down and the shadow gets reduced so it looks like
  // it might when typing on a physical keyboard.
  &:hover {
    box-shadow: 0 1px 0 0.5px var(--kbd-color-border);
    top: 1px;
Newer Weeknotes 2022-W02 Older The UX of dark mode toggles