Interaction blueprint
Checkbox path draw
A path draw confirms selection with a clear, accessible state change.
Build it
Choose a target and adapt the source to your interface.
<button
class="selection-control"
type="button"
role="checkbox"
aria-checked="false"
aria-label="Checkbox path draw"
>
<svg viewBox="0 0 24 24" aria-hidden="true">
<rect class="selection-box" x="3" y="3" width="18" height="18" rx="4" />
<path class="selection-check" d="m7 12 3 3 7-7" pathLength="1" />
</svg>
</button>
<script>
const control = document.querySelector('.selection-control');
control.addEventListener('click', () =>
control.setAttribute(
'aria-checked',
String(control.getAttribute('aria-checked') !== 'true'),
),
);
</script>
<style>
.selection-control {
display: inline-grid;
place-items: center;
width: 44px;
height: 44px;
padding: 10px;
border: 0;
border-radius: 6px;
background: transparent;
color: #175bc5;
cursor: pointer;
}
.selection-control svg {
width: 24px;
height: 24px;
overflow: visible;
}
.selection-control:focus-visible {
outline: 2px solid currentColor;
outline-offset: 4px;
}
.selection-outline {
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linejoin: round;
}
.selection-box {
fill: white;
stroke: currentColor;
stroke-width: 2;
transition: fill 80ms ease-out;
}
.selection-check {
fill: none;
stroke: white;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 1;
stroke-dashoffset: 1;
transition: stroke-dashoffset 140ms ease-out;
}
.selection-control[aria-checked='true'] .selection-box {
fill: currentColor;
}
.selection-control[aria-checked='true'] .selection-check {
stroke-dashoffset: 0;
transition-delay: 80ms;
}
@keyframes selection-pop {
0%,
100% {
transform: scale(1);
}
35% {
transform: scale(1.08);
}
}
@media (prefers-reduced-motion: reduce) {
.selection-control *,
.selection-control[aria-checked='true'] * {
animation: none;
transition: none;
}
}
</style>Animation breakdown
Frame phases, motion intent, implementation constraints and accessible alternatives.
01
Rest: empty square.
02
0–80ms: brand fill appears.
03
80–220ms: check path draws from lower left to upper right.
04
220–260ms: hold.
Motion intent
A path draw confirms selection with a clear, accessible state change.
This duration leaves enough time to read the state change while keeping the interface responsive.
The fast acceleration and long ease-out make the state feel responsive while giving the final pixels time to settle.
Motion specification
- Trigger
- A selection changes.
- Timing
- 260ms
- Easing
- cubic-bezier(.22, 1, .36, 1)
Animated properties
transformopacity
Implementation notes
- Keep unchecked and checked aligned to the same visual anchor.
- Drive the transition from semantic state, not a timer, when the trigger is interactive.
- Use transform, opacity and avoid layout work inside the animation loop.
Reduced motion
Swap to the final state instantly, preserving colour, label, and accessible state.
- Use a minimum 44 by 44 pixel interactive target.
- Expose the unchecked and checked states with aria-pressed, aria-expanded, or an updated accessible label.
- Keep visible keyboard focus independent from the animation.
Avoid
- Do not add bounce unless a real object pickup or spring settle is part of the interaction.
- Do not hide the final state from assistive technology.
- Do not make the user wait for animation before the underlying state updates.