AI CSS Animations

Color Swatch Radio Buttons

Round product color swatches. The chosen one grows an outline ring that springs out from its edge, draws a checkmark and shows its color name underneath. Colors live in one --sw each.

Also known as: color picker radio buttons css, product color swatches css, color selector radio.

HTML

<div class="rad-color-swatch-picker" role="radiogroup" aria-label="Color">
  <label><input type="radio" name="rad-color-swatch-picker" value="accent" checked><span class="rad-color-swatch-picker-dot"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg></span><span class="rad-color-swatch-picker-name">Accent</span></label>
  <label><input type="radio" name="rad-color-swatch-picker" value="rose"><span class="rad-color-swatch-picker-dot"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg></span><span class="rad-color-swatch-picker-name">Rose</span></label>
  <label><input type="radio" name="rad-color-swatch-picker" value="amber"><span class="rad-color-swatch-picker-dot"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg></span><span class="rad-color-swatch-picker-name">Amber</span></label>
  <label><input type="radio" name="rad-color-swatch-picker" value="mint"><span class="rad-color-swatch-picker-dot"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg></span><span class="rad-color-swatch-picker-name">Mint</span></label>
  <label><input type="radio" name="rad-color-swatch-picker" value="violet"><span class="rad-color-swatch-picker-dot"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg></span><span class="rad-color-swatch-picker-name">Violet</span></label>
</div>

CSS

.rad-color-swatch-picker {
  --c: var(--rad-color, #3b82f6);
  font-size: var(--rad-size, 18px);
  display: inline-flex;
  gap: 0.85em;
  padding-bottom: 1.4em;
  font-family: system-ui, sans-serif;
  line-height: 1.2;
}
.rad-color-swatch-picker label:nth-of-type(1) { --sw: var(--c); }
.rad-color-swatch-picker label:nth-of-type(2) { --sw: #f43f5e; }
.rad-color-swatch-picker label:nth-of-type(3) { --sw: #f59e0b; }
.rad-color-swatch-picker label:nth-of-type(4) { --sw: #10b981; }
.rad-color-swatch-picker label:nth-of-type(5) { --sw: #8b5cf6; }
.rad-color-swatch-picker label {
  position: relative;
  cursor: pointer;
}
.rad-color-swatch-picker input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
  z-index: 1;
}
.rad-color-swatch-picker-dot {
  display: grid;
  place-items: center;
  width: 2em;
  height: 2em;
  border-radius: 50%;
  background: var(--sw);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 15%, transparent);
  outline: 0.14em solid transparent;
  outline-offset: -0.14em;
  transition: outline-offset 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), outline-color 0.2s ease, transform 0.25s ease;
}
.rad-color-swatch-picker label:hover .rad-color-swatch-picker-dot {
  transform: scale(1.08);
}
.rad-color-swatch-picker-dot svg {
  width: 1.1em;
  height: 1.1em;
  fill: none;
  stroke: #fff;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
  transition: stroke-dashoffset 0.15s ease;
}
.rad-color-swatch-picker-name {
  position: absolute;
  top: 100%;
  left: 50%;
  margin-top: 0.5em;
  font-size: 0.72em;
  font-weight: 600;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, -0.4em);
  transition: opacity 0.2s ease, transform 0.3s ease;
}
.rad-color-swatch-picker input:checked + .rad-color-swatch-picker-dot {
  outline-color: var(--sw);
  outline-offset: 0.2em;
}
.rad-color-swatch-picker input:checked + .rad-color-swatch-picker-dot svg {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 0.3s ease 0.12s;
}
.rad-color-swatch-picker input:checked ~ .rad-color-swatch-picker-name {
  opacity: 1;
  transform: translate(-50%, 0);
}
.rad-color-swatch-picker input:focus-visible + .rad-color-swatch-picker-dot {
  outline: 0.14em dashed var(--sw);
  outline-offset: 0.2em;
}

@media (prefers-reduced-motion: reduce) {
  .rad-color-swatch-picker, .rad-color-swatch-picker *, .rad-color-swatch-picker::before, .rad-color-swatch-picker::after, .rad-color-swatch-picker *::before, .rad-color-swatch-picker *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --rad-color on the element or a parent. Currently previewing #3b82f6.
  • Size: set --rad-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 18px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar radio buttons