14 Material Design CSS Components 12 / 14

Material Design List CSS

Single-line, two-line with avatars, three-line with thumbnails, icon lists with subheaders and dividers, checkbox lists, and action-button rows — complete Material Design 3 list system.

Pure CSS MIT licensed
Live Demo Open in tab

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

Open in playground

The code

<div class="md-12">

  <!-- Single-line list -->
  <h3>Single-Line</h3>
  <div class="list-card">
    <div class="list-item">
      <div class="item-text"><div class="item-primary">Inbox</div></div>
      <div class="item-trailing"><div class="item-badge">12</div></div>
    </div>
    <div class="list-item">
      <div class="item-text"><div class="item-primary">Starred</div></div>
      <div class="item-trailing item-chevron">›</div>
    </div>
    <div class="list-item">
      <div class="item-text"><div class="item-primary">Sent</div></div>
    </div>
    <div class="list-item">
      <div class="item-text"><div class="item-primary">Drafts</div></div>
      <div class="item-trailing"><div class="item-badge">3</div></div>
    </div>
    <div class="list-item">
      <div class="item-text"><div class="item-primary">Trash</div></div>
    </div>
  </div>

  <!-- Two-line with avatars -->
  <h3>Two-Line with Avatars</h3>
  <div class="list-card">
    <div class="list-item list-item--two">
      <div class="item-avatar">J</div>
      <div class="item-text">
        <div class="item-primary">Jamie Lee</div>
        <div class="item-secondary">Hey! Are you free this weekend?</div>
      </div>
      <div class="item-trailing item-meta">2m</div>
    </div>
    <div class="list-item list-item--two">
      <div class="item-avatar" data-color="teal">A</div>
      <div class="item-text">
        <div class="item-primary">Alex Kim</div>
        <div class="item-secondary">The designs look great, nice work!</div>
      </div>
      <div class="item-trailing item-meta">1h</div>
    </div>
    <div class="list-item list-item--two">
      <div class="item-avatar" data-color="orange">M</div>
      <div class="item-text">
        <div class="item-primary">Morgan Blake</div>
        <div class="item-secondary">Can we reschedule the meeting?</div>
      </div>
      <div class="item-trailing item-meta">3h</div>
    </div>
    <div class="list-item list-item--two">
      <div class="item-avatar" data-color="purple">S</div>
      <div class="item-text">
        <div class="item-primary">Sam Rivera</div>
        <div class="item-secondary">Just sent over the report</div>
      </div>
      <div class="item-trailing item-meta">9h</div>
    </div>
    <div class="list-item list-item--two">
      <div class="item-avatar" data-color="red">T</div>
      <div class="item-text">
        <div class="item-primary">Taylor Brooks</div>
        <div class="item-secondary">Thanks for the introduction!</div>
      </div>
      <div class="item-trailing item-meta">1d</div>
    </div>
  </div>

  <!-- Three-line with image thumbnails -->
  <h3>Three-Line with Thumbnails</h3>
  <div class="list-card">
    <div class="list-item list-item--three">
      <div class="item-image">
        <svg viewBox="0 0 24 24"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>
      </div>
      <div class="item-text">
        <div class="item-primary">Summer Retreat 2024</div>
        <div class="item-secondary">Album · 48 photos</div>
        <div class="item-tertiary">Mountain views, campfire nights, and hiking trails across the national park.</div>
      </div>
    </div>
    <div class="list-item list-item--three">
      <div class="item-image">
        <svg viewBox="0 0 24 24"><path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/></svg>
      </div>
      <div class="item-text">
        <div class="item-primary">Late Night Mix</div>
        <div class="item-secondary">Playlist · 22 tracks</div>
        <div class="item-tertiary">Chill ambient and lo-fi beats for focused late-night work sessions.</div>
      </div>
    </div>
    <div class="list-item list-item--three">
      <div class="item-image">
        <svg viewBox="0 0 24 24"><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z"/></svg>
      </div>
      <div class="item-text">
        <div class="item-primary">Deep Work</div>
        <div class="item-secondary">Book · Cal Newport</div>
        <div class="item-tertiary">Rules for focused success in a distracted world — a must-read for knowledge workers.</div>
      </div>
    </div>
  </div>

  <!-- With icons + subheaders + dividers -->
  <h3>With Icons &amp; Subheaders</h3>
  <div class="list-card">
    <div class="list-subheader">General</div>
    <div class="list-item">
      <div class="item-icon"><svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg></div>
      <div class="item-text"><div class="item-primary">Account</div></div>
      <div class="item-trailing item-chevron">›</div>
    </div>
    <div class="list-item">
      <div class="item-icon"><svg viewBox="0 0 24 24"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"/></svg></div>
      <div class="item-text"><div class="item-primary">Notifications</div></div>
      <div class="item-trailing"><div class="item-switch item-switch--on"></div></div>
    </div>
    <div class="list-divider"></div>
    <div class="list-subheader">Display</div>
    <div class="list-item">
      <div class="item-icon"><svg viewBox="0 0 24 24"><path d="M20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12 20 8.69zM12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6 6 2.69 6 6-2.69 6-6 6zm0-10c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z"/></svg></div>
      <div class="item-text">
        <div class="item-primary">Dark Theme</div>
        <div class="item-secondary">Currently off</div>
      </div>
      <div class="item-trailing"><div class="item-switch"></div></div>
    </div>
    <div class="list-item">
      <div class="item-icon"><svg viewBox="0 0 24 24"><path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06z"/></svg></div>
      <div class="item-text"><div class="item-primary">Language &amp; Region</div></div>
      <div class="item-trailing item-chevron">›</div>
    </div>
  </div>

  <!-- Checkbox list -->
  <h3>Checkbox List</h3>
  <div class="list-card">
    <div class="list-item list-item--two">
      <div class="item-text">
        <div class="item-primary">Design system components</div>
        <div class="item-secondary">Buttons, chips, dialogs</div>
      </div>
      <div class="item-trailing"><div class="item-check item-check--on"></div></div>
    </div>
    <div class="list-item list-item--two">
      <div class="item-text">
        <div class="item-primary">Accessibility audit</div>
        <div class="item-secondary">WCAG 2.1 AA compliance</div>
      </div>
      <div class="item-trailing"><div class="item-check item-check--on"></div></div>
    </div>
    <div class="list-item list-item--two">
      <div class="item-text">
        <div class="item-primary">Dark mode theming</div>
        <div class="item-secondary">Token mapping &amp; overrides</div>
      </div>
      <div class="item-trailing"><div class="item-check"></div></div>
    </div>
    <div class="list-item list-item--two">
      <div class="item-text">
        <div class="item-primary">Documentation</div>
        <div class="item-secondary">Component usage &amp; API</div>
      </div>
      <div class="item-trailing"><div class="item-check"></div></div>
    </div>
  </div>

  <!-- Action buttons trailing -->
  <h3>With Action Buttons</h3>
  <div class="list-card">
    <div class="list-item list-item--two">
      <div class="item-avatar" data-color="green">K</div>
      <div class="item-text">
        <div class="item-primary">Kai Nakamura</div>
        <div class="item-secondary">Frontend Engineer</div>
      </div>
      <div class="item-trailing item-actions">
        <button class="item-action-btn"><svg viewBox="0 0 24 24"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></svg></button>
        <button class="item-action-btn"><svg viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg></button>
      </div>
    </div>
    <div class="list-item list-item--two">
      <div class="item-avatar" data-color="pink">P</div>
      <div class="item-text">
        <div class="item-primary">Priya Sharma</div>
        <div class="item-secondary">Product Designer</div>
      </div>
      <div class="item-trailing item-actions">
        <button class="item-action-btn"><svg viewBox="0 0 24 24"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></svg></button>
        <button class="item-action-btn"><svg viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg></button>
      </div>
    </div>
    <div class="list-item list-item--two">
      <div class="item-avatar" data-color="red">C</div>
      <div class="item-text">
        <div class="item-primary">Carlos Vega</div>
        <div class="item-secondary">Engineering Manager</div>
      </div>
      <div class="item-trailing item-actions">
        <button class="item-action-btn"><svg viewBox="0 0 24 24"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></svg></button>
        <button class="item-action-btn"><svg viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg></button>
      </div>
    </div>
  </div>

</div>
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');

.md-12 {
  --primary: #1976d2;
  --primary-light: #e3f2fd;
  --on-surface: #1c1b1f;
  --surface: #fffbfe;
  --surface-variant: #f3f3f3;
  --outline: #79747e;
  --outline-variant: #e0e0e0;
  all: unset;
  display: block;
  font-family: 'Roboto', sans-serif;
  background: #f5f5f5;
  padding: 32px 24px;
  box-sizing: border-box;
  color: var(--on-surface);
}
.md-12 *, .md-12 *::before, .md-12 *::after { box-sizing: border-box; margin: 0; padding: 0; }

.md-12 h3 {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--outline);
  margin-bottom: 4px;
  margin-top: 32px;
}
.md-12 h3:first-child { margin-top: 0; }

/* ── List card container ── */
.md-12 .list-card {
  background: var(--surface);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0,0,0,.1);
  margin-top: 8px;
}

/* ── Subheader ── */
.md-12 .list-subheader {
  padding: 8px 16px 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--primary);
  background: var(--primary-light);
}

/* ── List item base ── */
.md-12 .list-item {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 16px;
  min-height: 48px;
  cursor: pointer;
  position: relative;
  transition: background 150ms ease;
  border-bottom: 1px solid var(--outline-variant);
}
.md-12 .list-item:last-child { border-bottom: none; }
.md-12 .list-item:hover { background: rgba(25,118,210,.05); }
.md-12 .list-item:active { background: rgba(25,118,210,.1); }

/* Ripple */
.md-12 .list-item::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--primary);
  opacity: 0;
  border-radius: inherit;
  transition: opacity 400ms ease;
}
.md-12 .list-item:active::after { opacity: .06; transition: none; }

/* ── Two-line item ── */
.md-12 .list-item--two { min-height: 64px; }
.md-12 .list-item--three { min-height: 80px; align-items: flex-start; padding-top: 12px; padding-bottom: 12px; }

/* ── Text block ── */
.md-12 .item-text { flex: 1; min-width: 0; }
.md-12 .item-primary { font-size: 15px; font-weight: 400; color: var(--on-surface); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.md-12 .item-secondary { font-size: 13px; color: var(--outline); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.md-12 .item-tertiary { font-size: 12px; color: #aaa; margin-top: 1px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; white-space: normal; }

/* ── Leading avatar ── */
.md-12 .item-avatar {
  width: 40px; height: 40px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  font-size: 15px;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.md-12 .item-avatar--img {
  background-size: cover;
  background-position: center;
  font-size: 0;
}
/* Avatar color variants */
.md-12 .item-avatar[data-color="teal"]   { background: #00897b; }
.md-12 .item-avatar[data-color="orange"] { background: #f57c00; }
.md-12 .item-avatar[data-color="purple"] { background: #7b1fa2; }
.md-12 .item-avatar[data-color="red"]    { background: #c62828; }
.md-12 .item-avatar[data-color="green"]  { background: #388e3c; }
.md-12 .item-avatar[data-color="pink"]   { background: #d81b60; }

/* ── Leading icon ── */
.md-12 .item-icon {
  width: 24px; height: 24px;
  flex-shrink: 0;
  fill: var(--outline);
  display: flex; align-items: center; justify-content: center;
}
.md-12 .item-icon svg { width: 24px; height: 24px; }

/* ── Leading image ── */
.md-12 .item-image {
  width: 56px; height: 56px;
  border-radius: 4px;
  background: var(--outline-variant);
  flex-shrink: 0;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.md-12 .item-image svg { width: 28px; height: 28px; fill: #bbb; }

/* ── Trailing elements ── */
.md-12 .item-trailing { flex-shrink: 0; }
.md-12 .item-meta { font-size: 12px; color: var(--outline); }
.md-12 .item-badge {
  min-width: 20px; height: 20px;
  background: var(--primary);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  padding: 0 5px;
}
.md-12 .item-chevron { color: #bbb; font-size: 18px; }

/* ── Checkbox / radio trailing ── */
.md-12 .item-check {
  width: 18px; height: 18px;
  border: 2px solid var(--outline);
  border-radius: 3px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  transition: background 150ms, border-color 150ms;
}
.md-12 .item-check--on { background: var(--primary); border-color: var(--primary); }
.md-12 .item-check--on::after { content: ''; width: 10px; height: 6px; border-left: 2px solid #fff; border-bottom: 2px solid #fff; transform: rotate(-45deg) translate(1px,-1px); display: block; }

.md-12 .item-radio {
  width: 18px; height: 18px;
  border: 2px solid var(--outline);
  border-radius: 50%;
  flex-shrink: 0;
  position: relative;
  transition: border-color 150ms;
}
.md-12 .item-radio--on { border-color: var(--primary); }
.md-12 .item-radio--on::after { content: ''; width: 10px; height: 10px; background: var(--primary); border-radius: 50%; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); }

/* ── Switch trailing ── */
.md-12 .item-switch {
  width: 36px; height: 20px;
  background: #bdbdbd;
  border-radius: 10px;
  position: relative;
  transition: background 200ms;
  flex-shrink: 0;
}
.md-12 .item-switch::after {
  content: '';
  width: 16px; height: 16px;
  background: #fff;
  border-radius: 50%;
  position: absolute;
  top: 2px; left: 2px;
  transition: left 200ms, background 200ms;
  box-shadow: 0 1px 3px rgba(0,0,0,.3);
}
.md-12 .item-switch--on { background: var(--primary); }
.md-12 .item-switch--on::after { left: 18px; }

/* ── Divider ── */
.md-12 .list-divider {
  height: 1px;
  background: var(--outline-variant);
  margin: 0;
}
.md-12 .list-divider--inset { margin-left: 72px; }

/* ── Dense list ── */
.md-12 .list-item--dense { min-height: 36px; }
.md-12 .list-item--dense .item-primary { font-size: 13px; }

/* ── Action list (icon-button trailing) ── */
.md-12 .item-actions { display: flex; gap: 4px; }
.md-12 .item-action-btn {
  width: 32px; height: 32px;
  border-radius: 50%;
  border: none; background: transparent;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background 150ms;
  fill: var(--outline);
}
.md-12 .item-action-btn svg { width: 18px; height: 18px; }
.md-12 .item-action-btn:hover { background: rgba(0,0,0,.07); }
@media (prefers-reduced-motion: reduce) {
    .md-12 .list-item,
    .md-12 .list-item::after,
    .md-12 .item-switch,
    .md-12 .item-switch::after,
    .md-12 .item-check,
    .md-12 .item-action-btn { transition: none !important; }
  }

How this works

All list items are flex rows with align-items: center and a fixed min-height — 48px for single-line, 64px for two-line, 80px for three-line. Leading avatars are 40px circles with a background colour and a centred initial, rendered without images using CSS alone. Trailing elements (badges, chevrons, switches, checkboxes) are absolutely self-sized flex items that don't shrink.

Custom checkboxes and switches are styled native inputs hidden off-screen with matching visible labels. The switch uses a ::after thumb that slides 16px via translateX on the .item-switch--on modifier class. Subheaders use a coloured background: var(--primary-light) banner to visually group list sections, following the Material Design list section header pattern.

Customize

  • Change avatar size by editing width/height on .item-avatar — 48px gives a more prominent contact list feel.
  • Add swipe-to-delete by wrapping each list item in a container and sliding a red delete background on touch-start using a CSS translate transition.
  • Make the whole row tappable by wrapping item content in a <label for=checkbox> and removing the trailing-only click target.
  • Add a section index bar (alphabetical) by positioning an absolutely-placed letter list on the right edge of the list card.
  • Change list divider inset by editing margin-left: 72px on .list-divider--inset — 16px gives a full-width divider.

Watch out for

  • Three-line items clip long tertiary text with -webkit-line-clamp: 2 — this is a WebKit property now standardised but requires display: -webkit-box companion rule.
  • Switch .item-switch--on state cannot be toggled with pure CSS alone — in production, use a checkbox-hack or JavaScript classList.toggle.
  • Action button icons inside list rows must have a minimum 44×44px touch target — wrap with padding or use a 44px button with a smaller centred icon.

Browser support

ChromeSafariFirefoxEdge
88+ 14+ 89+ 88+

-webkit-line-clamp for three-line text truncation is supported in all modern browsers; no fallback needed for targets Chrome 88+, Safari 14+, Firefox 89+.

Search CodeFronts

Loading…