Tips・Copy-paste design snippets

CSS list design snippets you can copy and paste

Ready to graduate from plain black-dot bullets? Checkmarks, number badges, timelines, tag-style pills, and more—8 ready-to-use list designs, each with a live demo.

Left at their browser defaults, bulleted lists are just a row of plain black dots—a rather bland look. This article gathers 8 ready-to-use list designs, each with a live demo. Copy one and just swap the text for your own content.

HTMLBullet points with listsFor the basics of list HTML (ul and ol), head to this lesson of the HTML course

First, the shared groundwork

Remove the browser’s default black dots and left indent, and start from a clean slate. Every design assumes this reset.

.list {
  margin: 0;
  padding: 0;
  list-style: none;
}

The classic touches

Checkmark list

Instead of a black dot, place a green check—perfect for introducing “what you can do” or “key points.”

.check li {
  position: relative;
  padding-left: 32px;
}
.check li::before {
  content: "✓";
  position: absolute;
  left: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #2ec46f;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}

The trick is “remove the black dot, then place your own decoration on the left with ::before.” Just change the content to "★" or "→" and it becomes a different list.

Number-badge list

A numbered list for explaining steps. Turning the numbers into round badges makes it much easier to read. The numbers are assigned automatically by CSS using a mechanism called counter.

.steps {
  counter-reset: step;        /* where counting starts */
}
.steps li {
  counter-increment: step;    /* +1 for each line */
}
.steps li::before {
  content: counter(step);     /* show the number */
}

Even if you add a line in the middle, the numbers renumber themselves automatically. It’s far safer than writing the numbers by hand.

When you want two-digit numbers like “01” and “02,” just change the one content line.

.steps li::before {
  content: counter(step, decimal-leading-zero);
}

decimal-leading-zero means “add a 0 in front of single-digit numbers.” It gives a tidy impression, like the table of contents in a magazine.

Line-divided list

Instead of adding decorations, place one thin line between each row. It’s a staple for anything you want to keep quietly tidy, like a news list or a menu.

.news li {
  padding: 12px 4px;
  border-bottom: 1px solid #eee;
}

If the line left under the last row bothers you, add .news li:last-child { border-bottom: none; }. The flex-shrink: 0 on the date is a safeguard so the date doesn’t wrap even when the text gets long.

A “menu-style” list where each row is a link. When the arrow on the right slides on hover, it clearly signals that the row is clickable.

.menu a {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.menu a:hover span {
  transform: translateX(4px);
}

justify-content: space-between splits things into “text on the left, arrow on the right.” li + li means “the second row onward,” a way to keep the dividing line from being drawn above the first row.

Making a highlight

Timeline-style list

A shape that shows a “journey” with a vertical line and dots. Perfect for a learning log, a project history, or a profile career section.

.timeline::before {
  content: "";          /* the vertical line */
  position: absolute;
  width: 2px;
}
.timeline li::before {
  content: "";          /* the dot on each row */
  border-radius: 50%;
  border: 3px solid #fff;
}

The vertical line is the whole list’s ::before, and each dot is a row’s ::before—the roles are split. The white rim on the dots is the trick that makes them appear to float above the line.

Card-style list

Turn each row into a small card. Good for introducing features when you want the rows themselves to have presence.

.cards {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.cards li {
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);
}

The spacing between rows is managed all at once with gap. It won’t get cramped even as you add rows.

Tag / chip horizontal list

For a list of single words like “favorites” or “skills I can use,” laying them out as chips that flow horizontally is more compact than stacking them vertically.

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.tags li {
  padding: 6px 14px;
  border-radius: 999px;
}

flex-wrap: wrap is the setting for “wrap to the next line when they no longer fit.” No matter how many tags you add, the layout won’t break.

When you want to color the tags in a few different shades, use nth-child to apply colors in order—so you don’t have to touch the HTML.

.tags li:nth-child(3n+1) { background: #ffe8d6; color: #c05e1a; }
.tags li:nth-child(3n+2) { background: #e0f2e9; color: #1d7a4b; }
.tags li:nth-child(3n)   { background: #e3edff; color: #2b5cbf; }

3n+1 means “the 1st, 4th, 7th…” So three colors loop as they line up, and the tags get colored automatically even as you add more.

Horizontal definition-list style

For a profile that’s a series of “label: content” pairs, aligning the label column and the content column looks clean.

.profile li {
  display: flex;
}
.key {
  width: 110px;      /* align the label column width */
  flex-shrink: 0;
}

Just giving the label side a fixed width lines up the start of each content column, so it reads like a table.

A checklist for when a list looks wrong

  • The black dots won’t disappear → Writing list-style: none on the <ul> (or <ol>) applies it down to the <li> inside. If they still won’t go, check whether another CSS rule is overriding list-style on the <li> side
  • A mysterious gap remains on the left → That’s the browser’s default padding. Add padding: 0 to the <ul>
  • The ::before decoration doesn’t show → Did you forget to write content: ""? It’s required even when empty
  • The decoration’s position is off → The <li> side needs position: relative

Summary

  1. Every design starts with resetting the bullets and indent (list-style: none + padding: 0)
  2. Make decorations yourself with ::before—checks, number badges, timeline dots all use the same mechanism
  3. To lay things out horizontally, use display: flex + flex-wrap: wrap—you can apply it to tag-style and definition-list-style layouts
TipsCopy-and-paste CSS heading designsFor designs for the “heading” that sits above a list, see this copy-paste collection

Bulleted lists are a part that shows up on every page. Restyling just one of them tightens up the whole page.

FAQ

How do I remove the black dots (bullets) from a list?
Set list-style: none on the ul or ol and they disappear. The browser's default left indent still remains, so it's standard to add padding: 0 at the same time.
I heard that removing the bullets makes a screen reader stop treating it as a list?
In Safari's screen-reader setup that can happen. If it concerns you, add the attribute role="list" to the ul, and it will keep being announced as a list.