A round button that swirls six actions out into a ring around itself on hover. Each item is rotated, pushed out and rotated back, so the icons stay upright while they spiral into place.
Also known as: circular menu css, pie menu on hover, radial speed dial.
<nav class="hfx-radial-menu" aria-label="Quick actions"> <button class="hfx-radial-menu-toggle" aria-label="Show actions"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg></button> <a href="#" aria-label="Like" style="--i: 0"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 20s-7.5-4.6-7.5-10A4.3 4.3 0 0 1 12 7.2 4.3 4.3 0 0 1 19.5 10c0 5.4-7.5 10-7.5 10z"/></svg></a> <a href="#" aria-label="Share" style="--i: 1"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12M7.5 7.5 12 3l4.5 4.5M5 13v5.5A1.5 1.5 0 0 0 6.5 20h11a1.5 1.5 0 0 0 1.5-1.5V13"/></svg></a> <a href="#" aria-label="Save" style="--i: 2"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6.5 4h11v16.5L12 16.5l-5.5 4z"/></svg></a> <a href="#" aria-label="Copy link" style="--i: 3"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 14a4.5 4.5 0 0 0 6.4 0l3-3a4.5 4.5 0 0 0-6.4-6.4l-1 1"/><path d="M14 10a4.5 4.5 0 0 0-6.4 0l-3 3a4.5 4.5 0 0 0 6.4 6.4l1-1"/></svg></a> <a href="#" aria-label="Email" style="--i: 4"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="m3.5 7 8.5 6 8.5-6"/></svg></a> <a href="#" aria-label="Comment" style="--i: 5"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 11.5a7.5 7.5 0 0 1-10.9 6.7L4 19.5l1.3-4.6A7.5 7.5 0 1 1 20 11.5z"/></svg></a> </nav>
.hfx-radial-menu {
--c: var(--hfx-color, #3b82f6);
font-size: var(--hfx-size, 16px);
position: relative;
display: grid;
place-items: center;
width: 3.2em;
height: 3.2em;
}
/* an invisible disc that keeps the hover alive between the items */
.hfx-radial-menu::before {
content: "";
position: absolute;
inset: -4.2em;
border-radius: 50%;
transform: scale(0);
}
.hfx-radial-menu:is(:hover, :focus-within)::before { transform: scale(1); }
.hfx-radial-menu-toggle {
position: relative;
z-index: 1;
display: grid;
place-items: center;
width: 3.2em;
height: 3.2em;
padding: 0;
border: 0;
border-radius: 50%;
background: var(--c);
box-shadow: 0 0.5em 1em -0.4em color-mix(in srgb, var(--c) 80%, transparent);
color: #fff;
cursor: pointer;
transition: transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.hfx-radial-menu-toggle svg { width: 1.4em; height: 1.4em; }
.hfx-radial-menu a {
--a: calc(var(--i) * 60deg);
position: absolute;
top: 50%;
left: 50%;
display: grid;
place-items: center;
width: 2.3em;
height: 2.3em;
margin: -1.15em 0 0 -1.15em;
border: 1px solid color-mix(in srgb, var(--c) 35%, transparent);
border-radius: 50%;
background: color-mix(in srgb, var(--c) 12%, transparent);
color: var(--c);
opacity: 0;
transform: rotate(calc(var(--a) - 90deg)) translateY(0) rotate(calc(90deg - var(--a))) scale(0.4);
transition: transform 0.5s cubic-bezier(0.34, 1.4, 0.64, 1), opacity 0.2s ease, background-color 0.2s ease, color 0.2s ease, scale 0.2s ease;
transition-delay: calc(var(--i) * 30ms);
}
.hfx-radial-menu a svg { width: 1.1em; height: 1.1em; }
.hfx-radial-menu:is(:hover, :focus-within) .hfx-radial-menu-toggle { transform: rotate(135deg); }
.hfx-radial-menu:is(:hover, :focus-within) a {
opacity: 1;
transform: rotate(var(--a)) translateY(-4.3em) rotate(calc(-1 * var(--a))) scale(1);
}
.hfx-radial-menu a:is(:hover, :focus-visible) {
background: var(--c);
color: #fff;
scale: 1.12;
transition-delay: 0s;
}
@media (prefers-reduced-motion: reduce) {
.hfx-radial-menu, .hfx-radial-menu *, .hfx-radial-menu::before, .hfx-radial-menu::after, .hfx-radial-menu *::before, .hfx-radial-menu *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--hfx-color on the element or a parent.
Currently previewing #3b82f6.--hfx-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.