21 CSS Circular & Radial Menu Designs

Donut Sectors

A 6-sector SVG donut with curved labels following each arc via textPath. On hover the sector pulls outward (split effect), the label brightens, and a subtle scale animation runs. Real hit-tested wedges.

Pure CSS MIT licensed

Donut Sectors the 8th of 21 designs in the 21 CSS Circular & Radial Menu Designs collection. The design is implemented in pure CSS — no JavaScript required. Copy the HTML and CSS panels below into your project. Because the demo is pure CSS, it works in any framework or templating engine you happen to use. The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.

Live preview

Open in playground

The code

<svg class="ccm-donut" viewBox="0 0 200 200" role="navigation" aria-label="Donut menu">
  <defs>
    <path id="ccm-donut-arc-1" d="M 100 25 A 75 75 0 0 1 164.95 62.5" />
    <path id="ccm-donut-arc-2" d="M 164.95 62.5 A 75 75 0 0 1 164.95 137.5" />
    <path id="ccm-donut-arc-3" d="M 164.95 137.5 A 75 75 0 0 1 100 175" />
    <path id="ccm-donut-arc-4" d="M 35.05 137.5 A 75 75 0 0 1 35.05 62.5" />
    <path id="ccm-donut-arc-5" d="M 100 175 A 75 75 0 0 1 35.05 137.5" />
    <path id="ccm-donut-arc-6" d="M 35.05 62.5 A 75 75 0 0 1 100 25" />
  </defs>
  <a href="#" class="ccm-donut-s" style="--c: #7c6cff" aria-label="Plan">
    <path d="M 100 100 L 100 10 A 90 90 0 0 1 177.94 55 Z" fill="var(--c)" />
    <text class="ccm-donut-l">
      <textPath href="#ccm-donut-arc-1" startOffset="50%" text-anchor="middle">PLAN</textPath>
    </text>
  </a>
  <a href="#" class="ccm-donut-s" style="--c: #a78bfa" aria-label="Design">
    <path d="M 100 100 L 177.94 55 A 90 90 0 0 1 177.94 145 Z" fill="var(--c)" />
    <text class="ccm-donut-l">
      <textPath href="#ccm-donut-arc-2" startOffset="50%" text-anchor="middle">DESIGN</textPath>
    </text>
  </a>
  <a href="#" class="ccm-donut-s" style="--c: #ff6c8a" aria-label="Build">
    <path d="M 100 100 L 177.94 145 A 90 90 0 0 1 100 190 Z" fill="var(--c)" />
    <text class="ccm-donut-l">
      <textPath href="#ccm-donut-arc-3" startOffset="50%" text-anchor="middle">BUILD</textPath>
    </text>
  </a>
  <a href="#" class="ccm-donut-s" style="--c: #f5a84a" aria-label="Test">
    <path d="M 100 100 L 100 190 A 90 90 0 0 1 22.06 145 Z" fill="var(--c)" />
    <text class="ccm-donut-l">
      <textPath href="#ccm-donut-arc-5" startOffset="50%" text-anchor="middle">TEST</textPath>
    </text>
  </a>
  <a href="#" class="ccm-donut-s" style="--c: #2ecc8a" aria-label="Ship">
    <path d="M 100 100 L 22.06 145 A 90 90 0 0 1 22.06 55 Z" fill="var(--c)" />
    <text class="ccm-donut-l">
      <textPath href="#ccm-donut-arc-4" startOffset="50%" text-anchor="middle">SHIP</textPath>
    </text>
  </a>
  <a href="#" class="ccm-donut-s" style="--c: #00e5ff" aria-label="Learn">
    <path d="M 100 100 L 22.06 55 A 90 90 0 0 1 100 10 Z" fill="var(--c)" />
    <text class="ccm-donut-l">
      <textPath href="#ccm-donut-arc-6" startOffset="50%" text-anchor="middle">LEARN</textPath>
    </text>
  </a>
  <circle cx="100" cy="100" r="32" fill="#15151d" stroke="#17171f" stroke-width="3" />
  <text x="100" y="104" class="ccm-donut-c" text-anchor="middle">MENU</text>
</svg>
.ccm-donut {
  width: 200px;
  height: 200px;
  display: block;
  overflow: visible;
  font-family: ui-monospace, "SF Mono", monospace;
}

.ccm-donut-s {
  cursor: pointer;
  transform-origin: 100px 100px;
  transform: scale(1) translate(0, 0);
  transition:
    transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
    filter 0.2s;
  text-decoration: none;
  animation: ccm-donut-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
}

.ccm-donut-s path {
  stroke: #17171f;
  stroke-width: 2;
  transition: filter 0.2s;
}

.ccm-donut-l {
  font:
    700 10px/1 ui-monospace,
    monospace;
  fill: #fff;
  letter-spacing: 0.18em;
  pointer-events: none;
  opacity: 0.92;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

.ccm-donut-c {
  font:
    700 9px/1 ui-monospace,
    monospace;
  fill: #c4b5fd;
  letter-spacing: 0.16em;
  pointer-events: none;
}

.ccm-donut-s:nth-of-type(1):hover,
.ccm-donut-s:nth-of-type(1):focus-visible {
  transform: translate(4px, -4px);
}

.ccm-donut-s:nth-of-type(2):hover,
.ccm-donut-s:nth-of-type(2):focus-visible {
  transform: translate(6px, 0px);
}

.ccm-donut-s:nth-of-type(3):hover,
.ccm-donut-s:nth-of-type(3):focus-visible {
  transform: translate(4px, 4px);
}

.ccm-donut-s:nth-of-type(4):hover,
.ccm-donut-s:nth-of-type(4):focus-visible {
  transform: translate(-4px, 4px);
}

.ccm-donut-s:nth-of-type(5):hover,
.ccm-donut-s:nth-of-type(5):focus-visible {
  transform: translate(-6px, 0px);
}

.ccm-donut-s:nth-of-type(6):hover,
.ccm-donut-s:nth-of-type(6):focus-visible {
  transform: translate(-4px, -4px);
}

.ccm-donut-s:hover path,
.ccm-donut-s:focus-visible path {
  filter: brightness(1.18) saturate(1.1);
}

.ccm-donut-s:nth-of-type(1) {
  animation-delay: 0.05s;
}

.ccm-donut-s:nth-of-type(2) {
  animation-delay: 0.1s;
}

.ccm-donut-s:nth-of-type(3) {
  animation-delay: 0.15s;
}

.ccm-donut-s:nth-of-type(4) {
  animation-delay: 0.2s;
}

.ccm-donut-s:nth-of-type(5) {
  animation-delay: 0.25s;
}

.ccm-donut-s:nth-of-type(6) {
  animation-delay: 0.3s;
}

@keyframes ccm-donut-pop {
  from { opacity: 0; transform: scale(0.6); }
  to   { opacity: 1; transform: scale(1); }
}

Search CodeFronts

Loading…