A button has a simple job: start an action. But we also want to understand what happened when we pressed it. In this small experiment, we’ll make the connection between an action and its response visible.
Here’s where we’re going. Give it a few taps, then let’s take it apart.
01. Meaning before movement
Start with a real button, rather than a div. That gives us the browser’s keyboard and focus behaviour from the beginning. Since this button doesn’t submit a form, we’ll say so explicitly.
<button class="tinker-button" type="button">
Give it a tinker
<span aria-hidden="true">↗</span>
</button>
The arrow is a little visual companion. It doesn’t add a separate meaning, so a screen reader doesn’t need to announce it. The action stays in the text.
02. Give it a little weight
A yellow surface and a dark shadow give the button a small physical presence. The shadow isn’t blurred; it acts like a second layer underneath. Use padding and a minimum height instead of fixing every dimension.
.tinker-button {
display: inline-flex;
align-items: center;
gap: 1.5rem;
min-height: 52px;
padding: 14px 24px;
border: 1px solid #25213a;
background: #efb933;
color: #25213a;
font: inherit;
cursor: pointer;
box-shadow: 5px 5px 0 #25213a;
transition: transform 160ms, box-shadow 160ms;
}
Colour doesn’t carry the state on its own. Position and shadow tell the same story. If you substitute your project’s colours, keep that relationship intact.
03. Let it answer back
When pressed, the button moves towards its shadow. Keep a clear focus outline for someone using a keyboard. The central interaction now works without depending on a mouse hover.
.tinker-button:active {
transform: translate(4px, 4px);
box-shadow: 1px 1px 0 #25213a;
}
.tinker-button:focus-visible {
outline: 3px solid #4857ed;
outline-offset: 6px;
}
@media (prefers-reduced-motion: reduce) {
.tinker-button { transition: none; }
}
The live example above also has a click counter. That counter uses React state separately from this CSS example; it’s there to demonstrate that the button responds.
04. Your turn
Reduce the shadow to two pixels. Then remove it entirely. Which version serves this particular button? The answer doesn’t have to be the same for every interface.
- Can you reach the button with Tab?
- Can you activate it with Enter and Space?
- Does the label remain readable on a narrow screen?
- Is the pressed state clear when motion is reduced?
This little checklist is a useful starting point before taking the experiment into your own interface. Leave a comment below with what you changed or where you got stuck.
Opening the comments…