HTML List Generator

Proper ul, ol and dl markup from a list of items, with the ordered-list attributes people forget and the reason a list has to be a list.

Live output

Enable JavaScript to customise; default output below.

List type

ul when the order does not matter, ol when it does, dl for term and description pairs such as a glossary or metadata.

Items
  1. Required for a definition list, where it becomes the dd. Optional elsewhere, where it becomes a span.

  2. Required for a definition list, where it becomes the dd. Optional elsewhere, where it becomes a span.

  3. Required for a definition list, where it becomes the dd. Optional elsewhere, where it becomes a span.

Live preview list.html
<ul>
	<li>Install the plugin</li>
	<li><a href="/docs/licence">Add your licence key</a></li>
	<li>Run the first sync</li>
</ul>

Output is valid and updates as you type.

A list of things should be a list. A screen reader announces “list, 5 items” and lets the user jump through them; three lines separated by <br> announce as one run-on sentence, and nothing tells the reader how many there are or where one ends.

That is the entire argument for <ul> over a paragraph with bullets typed into it, and it is why a navigation menu, a set of steps and a glossary each want different markup rather than the same div with different classes.

How to use

  1. Pick the type. ul when the order does not matter, ol when it does, dl for term and description pairs.
  2. Add the items. A URL turns the item into a link; a description becomes the dd in a definition list and a span elsewhere.
  3. For an ordered list continuing after a paragraph, set the start number rather than restarting at one.

Example

An unordered list with one linked item:

<ul>
	<li>Install the plugin</li>
	<li><a href="/docs/licence">Add your licence key</a></li>
	<li>Run the first sync</li>
</ul>

An ordered list that continues from four, lettered:

<ol class="steps" start="4" type="a">
	<li>Open the settings screen</li>
	<li>Paste the key <span class="description">It is shown once</span></li>
	<li>Save</li>
</ol>

A definition list:

<dl class="meta">
	<dt><a href="/docs/keys">API key</a></dt>
	<dd>A 32-character secret, shown once when created.</dd>
</dl>

Pitfalls

<br> is not a list. It is a line break inside one block of text. Everything that makes a list useful to a screen reader, a search engine or a stylesheet comes from the list element.

start and type are semantic, not styling. type="a" changes what a screen reader announces; the CSS equivalent, list-style-type, does not, and is dropped entirely by some assistive technology. If the letter or the number is part of the meaning, use the attribute.

list-style: none can remove the list from the accessibility tree. Safari with VoiceOver stops announcing a list when its markers are removed that way. Adding role="list" back is the accepted workaround, and it is a genuine bug you have to work around rather than an opinion.

A <dl> is for pairs, not for layout. Term and description: a glossary, a set of metadata fields, a FAQ where the question is a term. It is not a two-column layout tool, although it was used as one for years.

Only <li> may be a child of <ul> or <ol>. Whitespace and comments are allowed; a stray <div> or <span> between items is invalid and behaves inconsistently. Put the wrapper inside the li.

A nested list goes inside the li, not between items. <ul><li>One<ul>…</ul></li></ul>, not <ul><li>One</li><ul>…</ul></ul>. The second is the commonest markup error in hand-written menus.

A javascript: URL is refused here. Escaping makes hostile text inert; it does not make a hostile link target inert, because the browser executes the scheme rather than displaying it. The field accepts http, https, mailto, tel and relative paths.

Compatibility

Everything runs in the browser: nothing is uploaded and nothing is stored.

Every value is HTML-escaped, so quotes, angle brackets and ampersands become entities and cannot break out of an attribute or close the list early. The hostile fixture in the test suite includes an item whose text is </li></ul><script>, whose class tries to add an event handler, and whose URL contains quotes and angle brackets; the expected output shows all of it inert.

Attributes are omitted rather than emitted empty, so the output is the markup you would have written by hand. start is left out when zero, reversed is a boolean attribute with no value, and type is left out for ordinary numbering.

start, reversed and type on <ol> are in every browser. reversed counts down from the start value or from the number of items, which is worth checking against your design when both are set.

Frequently asked questions

ul or ol?
ol if reordering the items would change the meaning: steps, rankings, anything referred to by number. ul otherwise. Navigation is a ul even though it looks ordered on the page.
When is a definition list right?
Term and description pairs. A glossary, a specification table that is not tabular, a set of metadata fields. If you are reaching for it to get two columns, use a grid instead.
How do I make a list horizontal?
CSS: display: flex on the list. Keep the markup as a list so it still announces as one, and check in Safari that the markers being removed has not taken the list semantics with it.
Do I need role="list"?
Only when your CSS sets list-style: none, and then only really for Safari. It is harmless to add and it documents the intent.
Can I nest lists?
Yes, inside an <li>. Nesting more than two deep usually means the structure wants headings rather than indentation.
Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.