14 Material Design CSS Components10 / 14

Pure CSSMIT licensed

Material Design Tooltip CSS

Plain and rich tooltips in four directions, linear progress (determinate and indeterminate), circular progress, notification badges, and page dot navigation — all pure CSS.

Published

Live Demo
Try it

This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.

The code

<div class="md-10">
  <div class="md-10__wrap">
    <div class="md-10__page-title">Material Design Tooltips &amp; Indicators</div>
    <div class="md-10__page-sub">Tooltips (all 4 positions + rich), progress bars, circular indicators and badge components — pure CSS</div>

    <!-- Tooltips -->
    <div class="md-10__section">
      <div class="md-10__section-title">Tooltips — Hover to See</div>
      <div style="display:flex;flex-wrap:wrap;gap:24px;align-items:center;justify-content:center;padding:24px 0">
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn">✏</button>
          <div class="md-10__tooltip md-10__tooltip--top">Edit item</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn" style="background:#c62828">🗑</button>
          <div class="md-10__tooltip md-10__tooltip--bottom">Delete permanently</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn" style="background:#7b1fa2">↗</button>
          <div class="md-10__tooltip md-10__tooltip--right">Share with team</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn" style="background:#1565c0">⚙</button>
          <div class="md-10__tooltip md-10__tooltip--left">Open settings</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__text-btn">Format options</button>
          <div class="md-10__tooltip md-10__tooltip--top">Bold, italic, underline, strikethrough</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__badge-btn">Keyboard shortcuts</button>
          <div class="md-10__tooltip md-10__tooltip--top" style="max-width:220px;white-space:normal">Press ⌘K to open the command palette, ⌘S to save, ⌘Z to undo.</div>
        </div>
      </div>
    </div>

    <!-- Rich Tooltip -->
    <div class="md-10__section">
      <div class="md-10__section-title">Rich Tooltip (Hover)</div>
      <div style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;justify-content:center;padding:24px 0">
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn" style="background:#ff8f00">★</button>
          <div class="md-10__tooltip md-10__tooltip--top md-10__tooltip--rich" style="bottom:calc(100% + 12px);min-width:240px">
            <div class="md-10__tt-title">Add to favourites</div>
            <div class="md-10__tt-body">Save this item to your favourites list to access it quickly from the sidebar.</div>
            <div class="md-10__tt-actions">
              <button class="md-10__tt-btn">Learn more</button>
              <button class="md-10__tt-btn" style="margin-left:auto">Got it</button>
            </div>
          </div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__text-btn">Privacy settings ℹ</button>
          <div class="md-10__tooltip md-10__tooltip--right md-10__tooltip--rich" style="left:calc(100% + 12px)">
            <div class="md-10__tt-title">Privacy controls</div>
            <div class="md-10__tt-body">Control who can see your profile and how your data is shared. Settings apply immediately.</div>
            <div class="md-10__tt-actions">
              <button class="md-10__tt-btn">Open settings</button>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- Linear Progress -->
    <div class="md-10__section">
      <div class="md-10__section-title">Linear Progress Indicators</div>
      <div class="md-10__progress-row">
        <div>
          <div class="md-10__progress-label"><span>Storage used</span><span>72%</span></div>
          <div class="md-10__progress-track"><div class="md-10__progress-fill" style="width:72%"></div></div>
        </div>
        <div>
          <div class="md-10__progress-label"><span>Upload complete</span><span>45%</span></div>
          <div class="md-10__progress-track" style="height:8px;border-radius:4px"><div class="md-10__progress-fill" style="width:45%;background:#1565c0"></div></div>
        </div>
        <div>
          <div class="md-10__progress-label"><span>Confidence score</span><span>94%</span></div>
          <div class="md-10__progress-track" style="height:6px;background:#c8e6c9"><div class="md-10__progress-fill" style="width:94%;background:#2e7d32"></div></div>
        </div>
        <div>
          <div class="md-10__progress-label"><span>Loading data…</span><span>Indeterminate</span></div>
          <div class="md-10__progress-track" style="overflow:hidden;position:relative"><div class="md-10__progress-fill md-10__progress-fill--indeterminate" style="position:absolute"></div></div>
        </div>
      </div>
    </div>

    <!-- Circular Progress -->
    <div class="md-10__section">
      <div class="md-10__section-title">Circular Progress Indicators</div>
      <div class="md-10__circular-row">
        <div style="text-align:center">
          <div class="md-10__circular">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" stroke-dasharray="131" stroke-dashoffset="33" style="stroke:var(--primary)"/></svg>
            <div class="md-10__circular-val">75%</div>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Progress</div>
        </div>
        <div style="text-align:center">
          <div class="md-10__circular">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" stroke-dasharray="131" stroke-dashoffset="72" style="stroke:#2e7d32"/></svg>
            <div class="md-10__circular-val" style="color:#2e7d32">45%</div>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Budget</div>
        </div>
        <div style="text-align:center">
          <div class="md-10__circular">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" stroke-dasharray="131" stroke-dashoffset="13" style="stroke:#e65100"/></svg>
            <div class="md-10__circular-val" style="color:#e65100">90%</div>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Capacity</div>
        </div>
        <div style="text-align:center">
          <div class="md-10__circular md-10__circular--spin">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" style="stroke:var(--primary)"/></svg>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Loading…</div>
        </div>
        <div style="text-align:center">
          <div class="md-10__circular md-10__circular--spin">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28" style="stroke:#fce4ec"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" style="stroke:#e91e63"/></svg>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Syncing</div>
        </div>
      </div>
    </div>

    <!-- Badges -->
    <div class="md-10__section">
      <div class="md-10__section-title">Badges</div>
      <div class="md-10__badge-demo-row">
        <div class="md-10__badge-wrap">
          <button class="md-10__icon-btn" style="background:#455a64">🔔</button>
          <div class="md-10__badge">3</div>
        </div>
        <div class="md-10__badge-wrap">
          <button class="md-10__icon-btn" style="background:#455a64">📧</button>
          <div class="md-10__badge">99+</div>
        </div>
        <div class="md-10__badge-wrap">
          <button class="md-10__icon-btn" style="background:#455a64">⚙</button>
          <div class="md-10__badge md-10__badge--dot"></div>
        </div>
        <div class="md-10__badge-wrap">
          <button class="md-10__text-btn">Inbox</button>
          <div class="md-10__badge md-10__badge--large" style="top:-8px;right:-8px">New</div>
        </div>
        <div class="md-10__badge-wrap">
          <button class="md-10__text-btn">Messages</button>
          <div class="md-10__badge" style="top:-6px;right:-6px;background:#2e7d32">12</div>
        </div>
      </div>

      <!-- Page indicator dots -->
      <div style="margin-top:28px">
        <div style="font-size:.78rem;color:var(--ink2);margin-bottom:12px">Page Indicator Dots</div>
        <div class="md-10__dots-row">
          <div class="md-10__dot"></div>
          <div class="md-10__dot md-10__dot--active"></div>
          <div class="md-10__dot"></div>
          <div class="md-10__dot"></div>
          <div class="md-10__dot"></div>
        </div>
      </div>
    </div>
  </div>
</div>
.md-10,
.md-10 *,
.md-10 *::before,
.md-10 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.md-10 ::selection {
  background: #00695c;
  color: #fff;
}

.md-10 {
  --primary: #00695c;
  --primary-l: #4db6ac;
  --secondary: #f57c00;
  --surface: #fff;
  --bg: #e0f2f1;
  --ink: #212121;
  --ink2: #546e7a;
  --ink3: #90a4ae;
  --divider: #b2dfdb;
  font-family: 'Roboto',sans-serif;
  background: var(--bg);
  min-height: 100vh;
  padding: 48px 24px 80px;
  color: var(--ink);
}

.md-10__wrap {
  max-width: 900px;
  margin: 0 auto;
}

.md-10__page-title {
  font-size: clamp(1.4rem,4vw,2rem);
  font-weight: 700;
  margin-bottom: 4px;
}

.md-10__page-sub {
  font-size: .9rem;
  color: var(--ink2);
  margin-bottom: 40px;
}

.md-10__section {
  background: var(--surface);
  border-radius: 12px;
  padding: 32px;
  margin-bottom: 24px;
  box-shadow: 0 1px 4px rgba(0,0,0,.1);
}

.md-10__section-title {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink2);
  margin-bottom: 24px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.md-10__section-title::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--divider);
}
/* ── TOOLTIP ── */

.md-10__tooltip-wrap {
  position: relative;
  display: inline-flex;
}

.md-10__tooltip {
  position: absolute;
  z-index: 10;
  background: #212121;
  color: #fff;
  font-size: .75rem;
  font-weight: 400;
  line-height: 1.4;
  padding: 6px 10px;
  border-radius: 4px;
  white-space: nowrap;
  max-width: 240px;
  white-space: normal;
  pointer-events: none;
  opacity: 0;
  transition: opacity .15s .1s,transform .15s .1s;
}
/* Arrow */

.md-10__tooltip::before {
  content: '';
  position: absolute;
  width: 0;
  height: 0;
}
/* Top tooltip */

.md-10__tooltip--top {
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
}

.md-10__tooltip--top::before {
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: #212121;
}

.md-10__tooltip-wrap:hover .md-10__tooltip--top {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
/* Bottom tooltip */

.md-10__tooltip--bottom {
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(-4px);
}

.md-10__tooltip--bottom::before {
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-bottom-color: #212121;
}

.md-10__tooltip-wrap:hover .md-10__tooltip--bottom {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
/* Left tooltip */

.md-10__tooltip--left {
  right: calc(100% + 8px);
  top: 50%;
  transform: translateY(-50%) translateX(4px);
}

.md-10__tooltip--left::before {
  left: 100%;
  top: 50%;
  transform: translateY(-50%);
  border: 5px solid transparent;
  border-left-color: #212121;
}

.md-10__tooltip-wrap:hover .md-10__tooltip--left {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
/* Right tooltip */

.md-10__tooltip--right {
  left: calc(100% + 8px);
  top: 50%;
  transform: translateY(-50%) translateX(-4px);
}

.md-10__tooltip--right::before {
  right: 100%;
  top: 50%;
  transform: translateY(-50%);
  border: 5px solid transparent;
  border-right-color: #212121;
}

.md-10__tooltip-wrap:hover .md-10__tooltip--right {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
/* Rich tooltip */

.md-10__tooltip--rich {
  background: var(--surface);
  color: var(--ink);
  max-width: 280px;
  padding: 12px 16px;
  box-shadow: 0 2px 12px rgba(0,0,0,.2);
  border-radius: 8px;
  white-space: normal;
}

.md-10__tooltip--rich::before {
  display: none;
}

.md-10__tooltip--rich .md-10__tt-title {
  font-size: .875rem;
  font-weight: 700;
  margin-bottom: 4px;
  color: var(--ink);
}

.md-10__tooltip--rich .md-10__tt-body {
  font-size: .8rem;
  line-height: 1.5;
  color: var(--ink2);
}

.md-10__tooltip--rich .md-10__tt-actions {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--divider);
}

.md-10__tooltip--rich .md-10__tt-btn {
  background: none;
  border: none;
  color: var(--primary);
  font-family: 'Roboto';
  font-size: .78rem;
  font-weight: 500;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: .05em;
  padding: 0;
}
/* ── TRIGGER BUTTONS ── */

.md-10__icon-btn {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  background: var(--primary);
  color: #fff;
  font-size: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 6px rgba(0,0,0,.2);
  transition: box-shadow .2s;
}

.md-10__icon-btn:hover {
  box-shadow: 0 4px 12px rgba(0,0,0,.25);
}

.md-10__text-btn {
  height: 36px;
  padding: 0 16px;
  border: 1px solid var(--divider);
  border-radius: 4px;
  background: var(--surface);
  font-family: 'Roboto';
  font-size: .875rem;
  cursor: pointer;
  color: var(--ink);
}

.md-10__badge-btn {
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 10px 16px;
  font-family: 'Roboto';
  font-size: .875rem;
  font-weight: 500;
  cursor: pointer;
}
/* ── PROGRESS INDICATORS ── */

.md-10__progress-row {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.md-10__progress-label {
  font-size: .8rem;
  color: var(--ink2);
  margin-bottom: 6px;
  display: flex;
  justify-content: space-between;
}

.md-10__progress-track {
  height: 4px;
  background: #b2dfdb;
  border-radius: 2px;
  overflow: hidden;
  position: relative;
}

.md-10__progress-fill {
  height: 100%;
  background: var(--primary);
  border-radius: 2px;
  position: relative;
}
/* Indeterminate bar */

.md-10__progress-fill--indeterminate {
  width: 30%;
  animation: md10-indeterminate 2s linear infinite;
}

@keyframes md10-indeterminate {
  0% {
    left: -30%;
    width: 30%;
  }

  60% {
    left: 60%;
    width: 50%;
  }

  100% {
    left: 110%;
    width: 30%;
  }
}
/* Circular progress */

.md-10__circular-row {
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
}

.md-10__circular {
  position: relative;
  width: 64px;
  height: 64px;
  flex-shrink: 0;
}

.md-10__circular svg {
  transform: rotate(-90deg);
  width: 64px;
  height: 64px;
}

.md-10__circular-track {
  fill: none;
  stroke: #b2dfdb;
  stroke-width: 4;
}

.md-10__circular-fill {
  fill: none;
  stroke: var(--primary);
  stroke-width: 4;
  stroke-linecap: round;
  transition: stroke-dashoffset .5s ease;
}

.md-10__circular-val {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .8rem;
  font-weight: 700;
  color: var(--primary);
}
/* Indeterminate circle */

.md-10__circular--spin .md-10__circular-fill {
  stroke-dasharray: 160 200;
  animation: md10-cspin 1.4s linear infinite;
}

@keyframes md10-cspin {
  0% {
    stroke-dashoffset: 0;
    transform: none;
  }

  100% {
    stroke-dashoffset: -320;
    transform: none;
  }
}

.md-10__circular--spin svg {
  animation: md10-svg-spin 1.4s linear infinite;
}

@keyframes md10-svg-spin {
  0% {
    transform: rotate(-90deg);
  }

  100% {
    transform: rotate(270deg);
  }
}
/* ── BADGE ── */

.md-10__badge-wrap {
  position: relative;
  display: inline-flex;
}

.md-10__badge {
  position: absolute;
  top: -4px;
  right: -4px;
  background: var(--secondary);
  color: #fff;
  font-size: .65rem;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 10px;
  border: 2px solid var(--surface);
  line-height: 1.4;
  white-space: nowrap;
  min-width: 20px;
  text-align: center;
}

.md-10__badge--dot {
  width: 10px;
  height: 10px;
  min-width: 0;
  padding: 0;
  top: -2px;
  right: -2px;
}

.md-10__badge--large {
  font-size: .75rem;
  padding: 3px 8px;
  border-radius: 12px;
}

.md-10__badge-demo-row {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
  align-items: center;
}
/* ── PROGRESS OVERFLOW DOTS ── */

.md-10__dots-row {
  display: flex;
  gap: 4px;
  align-items: center;
  justify-content: center;
  padding: 8px 0;
}

.md-10__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--divider);
  transition: all .2s;
}

.md-10__dot--active {
  background: var(--primary);
  width: 24px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  .md-10 * {
    animation: none!important;
    transition: none!important;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Material Design Tooltip CSS
Source: https://codefronts.com/design-styles/css-material-designs/material-design-tooltip-css/

Plain and rich tooltips in four directions, linear progress (determinate and indeterminate), circular progress, notification badges, and page dot navigation — all pure CSS.
## HTML
```html
<div class="md-10">
  <div class="md-10__wrap">
    <div class="md-10__page-title">Material Design Tooltips &amp; Indicators</div>
    <div class="md-10__page-sub">Tooltips (all 4 positions + rich), progress bars, circular indicators and badge components — pure CSS</div>

    <!-- Tooltips -->
    <div class="md-10__section">
      <div class="md-10__section-title">Tooltips — Hover to See</div>
      <div style="display:flex;flex-wrap:wrap;gap:24px;align-items:center;justify-content:center;padding:24px 0">
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn">✏</button>
          <div class="md-10__tooltip md-10__tooltip--top">Edit item</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn" style="background:#c62828">🗑</button>
          <div class="md-10__tooltip md-10__tooltip--bottom">Delete permanently</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn" style="background:#7b1fa2">↗</button>
          <div class="md-10__tooltip md-10__tooltip--right">Share with team</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn" style="background:#1565c0">⚙</button>
          <div class="md-10__tooltip md-10__tooltip--left">Open settings</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__text-btn">Format options</button>
          <div class="md-10__tooltip md-10__tooltip--top">Bold, italic, underline, strikethrough</div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__badge-btn">Keyboard shortcuts</button>
          <div class="md-10__tooltip md-10__tooltip--top" style="max-width:220px;white-space:normal">Press ⌘K to open the command palette, ⌘S to save, ⌘Z to undo.</div>
        </div>
      </div>
    </div>

    <!-- Rich Tooltip -->
    <div class="md-10__section">
      <div class="md-10__section-title">Rich Tooltip (Hover)</div>
      <div style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;justify-content:center;padding:24px 0">
        <div class="md-10__tooltip-wrap">
          <button class="md-10__icon-btn" style="background:#ff8f00">★</button>
          <div class="md-10__tooltip md-10__tooltip--top md-10__tooltip--rich" style="bottom:calc(100% + 12px);min-width:240px">
            <div class="md-10__tt-title">Add to favourites</div>
            <div class="md-10__tt-body">Save this item to your favourites list to access it quickly from the sidebar.</div>
            <div class="md-10__tt-actions">
              <button class="md-10__tt-btn">Learn more</button>
              <button class="md-10__tt-btn" style="margin-left:auto">Got it</button>
            </div>
          </div>
        </div>
        <div class="md-10__tooltip-wrap">
          <button class="md-10__text-btn">Privacy settings ℹ</button>
          <div class="md-10__tooltip md-10__tooltip--right md-10__tooltip--rich" style="left:calc(100% + 12px)">
            <div class="md-10__tt-title">Privacy controls</div>
            <div class="md-10__tt-body">Control who can see your profile and how your data is shared. Settings apply immediately.</div>
            <div class="md-10__tt-actions">
              <button class="md-10__tt-btn">Open settings</button>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- Linear Progress -->
    <div class="md-10__section">
      <div class="md-10__section-title">Linear Progress Indicators</div>
      <div class="md-10__progress-row">
        <div>
          <div class="md-10__progress-label"><span>Storage used</span><span>72%</span></div>
          <div class="md-10__progress-track"><div class="md-10__progress-fill" style="width:72%"></div></div>
        </div>
        <div>
          <div class="md-10__progress-label"><span>Upload complete</span><span>45%</span></div>
          <div class="md-10__progress-track" style="height:8px;border-radius:4px"><div class="md-10__progress-fill" style="width:45%;background:#1565c0"></div></div>
        </div>
        <div>
          <div class="md-10__progress-label"><span>Confidence score</span><span>94%</span></div>
          <div class="md-10__progress-track" style="height:6px;background:#c8e6c9"><div class="md-10__progress-fill" style="width:94%;background:#2e7d32"></div></div>
        </div>
        <div>
          <div class="md-10__progress-label"><span>Loading data…</span><span>Indeterminate</span></div>
          <div class="md-10__progress-track" style="overflow:hidden;position:relative"><div class="md-10__progress-fill md-10__progress-fill--indeterminate" style="position:absolute"></div></div>
        </div>
      </div>
    </div>

    <!-- Circular Progress -->
    <div class="md-10__section">
      <div class="md-10__section-title">Circular Progress Indicators</div>
      <div class="md-10__circular-row">
        <div style="text-align:center">
          <div class="md-10__circular">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" stroke-dasharray="131" stroke-dashoffset="33" style="stroke:var(--primary)"/></svg>
            <div class="md-10__circular-val">75%</div>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Progress</div>
        </div>
        <div style="text-align:center">
          <div class="md-10__circular">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" stroke-dasharray="131" stroke-dashoffset="72" style="stroke:#2e7d32"/></svg>
            <div class="md-10__circular-val" style="color:#2e7d32">45%</div>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Budget</div>
        </div>
        <div style="text-align:center">
          <div class="md-10__circular">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" stroke-dasharray="131" stroke-dashoffset="13" style="stroke:#e65100"/></svg>
            <div class="md-10__circular-val" style="color:#e65100">90%</div>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Capacity</div>
        </div>
        <div style="text-align:center">
          <div class="md-10__circular md-10__circular--spin">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" style="stroke:var(--primary)"/></svg>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Loading…</div>
        </div>
        <div style="text-align:center">
          <div class="md-10__circular md-10__circular--spin">
            <svg viewBox="0 0 64 64"><circle class="md-10__circular-track" cx="32" cy="32" r="28" style="stroke:#fce4ec"/><circle class="md-10__circular-fill" cx="32" cy="32" r="28" style="stroke:#e91e63"/></svg>
          </div>
          <div style="font-size:.75rem;color:var(--ink2);margin-top:6px">Syncing</div>
        </div>
      </div>
    </div>

    <!-- Badges -->
    <div class="md-10__section">
      <div class="md-10__section-title">Badges</div>
      <div class="md-10__badge-demo-row">
        <div class="md-10__badge-wrap">
          <button class="md-10__icon-btn" style="background:#455a64">🔔</button>
          <div class="md-10__badge">3</div>
        </div>
        <div class="md-10__badge-wrap">
          <button class="md-10__icon-btn" style="background:#455a64">📧</button>
          <div class="md-10__badge">99+</div>
        </div>
        <div class="md-10__badge-wrap">
          <button class="md-10__icon-btn" style="background:#455a64">⚙</button>
          <div class="md-10__badge md-10__badge--dot"></div>
        </div>
        <div class="md-10__badge-wrap">
          <button class="md-10__text-btn">Inbox</button>
          <div class="md-10__badge md-10__badge--large" style="top:-8px;right:-8px">New</div>
        </div>
        <div class="md-10__badge-wrap">
          <button class="md-10__text-btn">Messages</button>
          <div class="md-10__badge" style="top:-6px;right:-6px;background:#2e7d32">12</div>
        </div>
      </div>

      <!-- Page indicator dots -->
      <div style="margin-top:28px">
        <div style="font-size:.78rem;color:var(--ink2);margin-bottom:12px">Page Indicator Dots</div>
        <div class="md-10__dots-row">
          <div class="md-10__dot"></div>
          <div class="md-10__dot md-10__dot--active"></div>
          <div class="md-10__dot"></div>
          <div class="md-10__dot"></div>
          <div class="md-10__dot"></div>
        </div>
      </div>
    </div>
  </div>
</div>
```
## CSS
```css
.md-10,
.md-10 *,
.md-10 *::before,
.md-10 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.md-10 ::selection {
  background: #00695c;
  color: #fff;
}

.md-10 {
  --primary: #00695c;
  --primary-l: #4db6ac;
  --secondary: #f57c00;
  --surface: #fff;
  --bg: #e0f2f1;
  --ink: #212121;
  --ink2: #546e7a;
  --ink3: #90a4ae;
  --divider: #b2dfdb;
  font-family: 'Roboto',sans-serif;
  background: var(--bg);
  min-height: 100vh;
  padding: 48px 24px 80px;
  color: var(--ink);
}

.md-10__wrap {
  max-width: 900px;
  margin: 0 auto;
}

.md-10__page-title {
  font-size: clamp(1.4rem,4vw,2rem);
  font-weight: 700;
  margin-bottom: 4px;
}

.md-10__page-sub {
  font-size: .9rem;
  color: var(--ink2);
  margin-bottom: 40px;
}

.md-10__section {
  background: var(--surface);
  border-radius: 12px;
  padding: 32px;
  margin-bottom: 24px;
  box-shadow: 0 1px 4px rgba(0,0,0,.1);
}

.md-10__section-title {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink2);
  margin-bottom: 24px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.md-10__section-title::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--divider);
}
/* ── TOOLTIP ── */

.md-10__tooltip-wrap {
  position: relative;
  display: inline-flex;
}

.md-10__tooltip {
  position: absolute;
  z-index: 10;
  background: #212121;
  color: #fff;
  font-size: .75rem;
  font-weight: 400;
  line-height: 1.4;
  padding: 6px 10px;
  border-radius: 4px;
  white-space: nowrap;
  max-width: 240px;
  white-space: normal;
  pointer-events: none;
  opacity: 0;
  transition: opacity .15s .1s,transform .15s .1s;
}
/* Arrow */

.md-10__tooltip::before {
  content: '';
  position: absolute;
  width: 0;
  height: 0;
}
/* Top tooltip */

.md-10__tooltip--top {
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
}

.md-10__tooltip--top::before {
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: #212121;
}

.md-10__tooltip-wrap:hover .md-10__tooltip--top {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
/* Bottom tooltip */

.md-10__tooltip--bottom {
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(-4px);
}

.md-10__tooltip--bottom::before {
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-bottom-color: #212121;
}

.md-10__tooltip-wrap:hover .md-10__tooltip--bottom {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
/* Left tooltip */

.md-10__tooltip--left {
  right: calc(100% + 8px);
  top: 50%;
  transform: translateY(-50%) translateX(4px);
}

.md-10__tooltip--left::before {
  left: 100%;
  top: 50%;
  transform: translateY(-50%);
  border: 5px solid transparent;
  border-left-color: #212121;
}

.md-10__tooltip-wrap:hover .md-10__tooltip--left {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
/* Right tooltip */

.md-10__tooltip--right {
  left: calc(100% + 8px);
  top: 50%;
  transform: translateY(-50%) translateX(-4px);
}

.md-10__tooltip--right::before {
  right: 100%;
  top: 50%;
  transform: translateY(-50%);
  border: 5px solid transparent;
  border-right-color: #212121;
}

.md-10__tooltip-wrap:hover .md-10__tooltip--right {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
/* Rich tooltip */

.md-10__tooltip--rich {
  background: var(--surface);
  color: var(--ink);
  max-width: 280px;
  padding: 12px 16px;
  box-shadow: 0 2px 12px rgba(0,0,0,.2);
  border-radius: 8px;
  white-space: normal;
}

.md-10__tooltip--rich::before {
  display: none;
}

.md-10__tooltip--rich .md-10__tt-title {
  font-size: .875rem;
  font-weight: 700;
  margin-bottom: 4px;
  color: var(--ink);
}

.md-10__tooltip--rich .md-10__tt-body {
  font-size: .8rem;
  line-height: 1.5;
  color: var(--ink2);
}

.md-10__tooltip--rich .md-10__tt-actions {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--divider);
}

.md-10__tooltip--rich .md-10__tt-btn {
  background: none;
  border: none;
  color: var(--primary);
  font-family: 'Roboto';
  font-size: .78rem;
  font-weight: 500;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: .05em;
  padding: 0;
}
/* ── TRIGGER BUTTONS ── */

.md-10__icon-btn {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  background: var(--primary);
  color: #fff;
  font-size: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 6px rgba(0,0,0,.2);
  transition: box-shadow .2s;
}

.md-10__icon-btn:hover {
  box-shadow: 0 4px 12px rgba(0,0,0,.25);
}

.md-10__text-btn {
  height: 36px;
  padding: 0 16px;
  border: 1px solid var(--divider);
  border-radius: 4px;
  background: var(--surface);
  font-family: 'Roboto';
  font-size: .875rem;
  cursor: pointer;
  color: var(--ink);
}

.md-10__badge-btn {
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 10px 16px;
  font-family: 'Roboto';
  font-size: .875rem;
  font-weight: 500;
  cursor: pointer;
}
/* ── PROGRESS INDICATORS ── */

.md-10__progress-row {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.md-10__progress-label {
  font-size: .8rem;
  color: var(--ink2);
  margin-bottom: 6px;
  display: flex;
  justify-content: space-between;
}

.md-10__progress-track {
  height: 4px;
  background: #b2dfdb;
  border-radius: 2px;
  overflow: hidden;
  position: relative;
}

.md-10__progress-fill {
  height: 100%;
  background: var(--primary);
  border-radius: 2px;
  position: relative;
}
/* Indeterminate bar */

.md-10__progress-fill--indeterminate {
  width: 30%;
  animation: md10-indeterminate 2s linear infinite;
}

@keyframes md10-indeterminate {
  0% {
    left: -30%;
    width: 30%;
  }

  60% {
    left: 60%;
    width: 50%;
  }

  100% {
    left: 110%;
    width: 30%;
  }
}
/* Circular progress */

.md-10__circular-row {
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
}

.md-10__circular {
  position: relative;
  width: 64px;
  height: 64px;
  flex-shrink: 0;
}

.md-10__circular svg {
  transform: rotate(-90deg);
  width: 64px;
  height: 64px;
}

.md-10__circular-track {
  fill: none;
  stroke: #b2dfdb;
  stroke-width: 4;
}

.md-10__circular-fill {
  fill: none;
  stroke: var(--primary);
  stroke-width: 4;
  stroke-linecap: round;
  transition: stroke-dashoffset .5s ease;
}

.md-10__circular-val {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .8rem;
  font-weight: 700;
  color: var(--primary);
}
/* Indeterminate circle */

.md-10__circular--spin .md-10__circular-fill {
  stroke-dasharray: 160 200;
  animation: md10-cspin 1.4s linear infinite;
}

@keyframes md10-cspin {
  0% {
    stroke-dashoffset: 0;
    transform: none;
  }

  100% {
    stroke-dashoffset: -320;
    transform: none;
  }
}

.md-10__circular--spin svg {
  animation: md10-svg-spin 1.4s linear infinite;
}

@keyframes md10-svg-spin {
  0% {
    transform: rotate(-90deg);
  }

  100% {
    transform: rotate(270deg);
  }
}
/* ── BADGE ── */

.md-10__badge-wrap {
  position: relative;
  display: inline-flex;
}

.md-10__badge {
  position: absolute;
  top: -4px;
  right: -4px;
  background: var(--secondary);
  color: #fff;
  font-size: .65rem;
  font-weight: 700;
  padding: 2px 6px;
  border-radius: 10px;
  border: 2px solid var(--surface);
  line-height: 1.4;
  white-space: nowrap;
  min-width: 20px;
  text-align: center;
}

.md-10__badge--dot {
  width: 10px;
  height: 10px;
  min-width: 0;
  padding: 0;
  top: -2px;
  right: -2px;
}

.md-10__badge--large {
  font-size: .75rem;
  padding: 3px 8px;
  border-radius: 12px;
}

.md-10__badge-demo-row {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
  align-items: center;
}
/* ── PROGRESS OVERFLOW DOTS ── */

.md-10__dots-row {
  display: flex;
  gap: 4px;
  align-items: center;
  justify-content: center;
  padding: 8px 0;
}

.md-10__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--divider);
  transition: all .2s;
}

.md-10__dot--active {
  background: var(--primary);
  width: 24px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  .md-10 * {
    animation: none!important;
    transition: none!important;
  }
}
```

How this works

Plain tooltips are ::after pseudo-elements on a .tooltip wrapper set to opacity: 0; pointer-events: none by default. On :hover and :focus-within, opacity transitions to 1 and a small translateY closes the gap, giving the Material enter animation. Direction variants (--top, --right, --bottom, --left) use absolute positioning offset from the anchor.

Linear progress tracks are height: 4px containers with a child fill element. Determinate fill uses an inline width percentage; indeterminate runs a @keyframes that slides the fill from -35% to 110% and a second keyframe that scales it from 0.35 to 0.65 — matching the exact Material indeterminate behaviour. Circular progress uses stroke-dasharray/stroke-dashoffset on an SVG circle.

Make it yours

  • Change tooltip max-width by editing the max-width on .tooltip::after from 200px to a wider value for rich content.
  • Delay tooltip appearance by adding transition-delay: 400ms to the opacity transition so it only shows on sustained hover.
  • Make progress bars animated on page load by adding a @keyframes that grows width from 0 to the target percentage over 600ms.
  • Change circular progress stroke colour by editing stroke on the foreground circle element.
  • Adjust badge position by modifying the top/right offset on the .badge absolute positioning.

Gotchas — read before shipping

  • Tooltip pseudo-elements on <button> work in Chrome and Firefox but Safari requires a non-replaced element as the anchor — wrap the button in a <span> if needed.
  • The indeterminate linear progress animation runs indefinitely — pause it with animation-play-state: paused when the loading state resolves.
  • SVG stroke-dashoffset for circular progress requires knowing the circle circumference (2πr) — changing the SVG r attribute means recalculating the dasharray value.

Browser support

ChromeSafariFirefoxEdge
88+14+89+88+

SVG stroke-dasharray animation is supported in all modern browsers; the indeterminate linear animation uses standard keyframes with no vendor prefixes needed.

Techniques used in this demo

Search CodeFronts

Loading…