easylist

A LaTeX list runs out of road at four levels. easylist gets past that wall by giving up on nested environments altogether: inside \begin{easylist} the number of # characters is the depth, so ### is level three and ##### is level five. No \item, no nested \begin. The package also ships a preset called tractatus, which reproduces the numbering of Wittgenstein's Tractatus Logico-Philosophicus exactly. This page covers how easylist is written, where the real ceiling is (ten levels, and the error it raises), and when it beats enumitem and when it does not — every claim set and measured on TeX Live 2024.

How easylist works: the count of # is the level

Load it as \usepackage[sharp]{easylist} and, inside the easylist environment, start each line with a run of #. One # is level 1, ## is level 2. Always put exactly one space after the run of markers. You never write \item — there is nowhere to put it. Because easylist builds no nested environments, depth is not a matter of how many \begin are open but purely of how many # that one line carries. That is why the depth is described as unlimited, and it is also why you can jump up and down between levels anywhere in the list.

document.tex
\documentclass{article}
\usepackage[sharp]{easylist}
\begin{document}
\begin{easylist}
# First proposition.
## Interesting comment.
### A note on the comment.
### Another note.
#### By the way...
# Let's start something new.
\end{easylist}
\end{document}

Set that on TeX Live 2024 and the numbers come out 1. 1.1. 1.1.1. 1.1.2. 1.1.2.1. 2. — the level counters joined by periods, with a period after the last one too. That trailing period is FinalMark, and it can be removed. Skipping a level counts the skipped level as zero: put ### straight after a level-1 item and the number reads 1.0.1., with no error. Forget the space after the markers, though, and it breaks quietly. Writing #With no space. printed that item with no number at all, and the following ## line then came out as 0.0.1. — not just a missing label but a shifted counter for everything after it.

The real ceiling is ten levels: fixing the Too many error

“No depth limit” is not quite true. Ten levels of counters are created by default, and an eleventh stops the run. Feeding a fourteen-level list through TeX Live 2024 produced ! Package easylist Error: followed by three lines beginning ==> Too many, whose message is that you cannot use more than ten markers unless you say so when loading the package. And the PDF it still wrote showed every item from level eleven on carrying the literal text !!! where its number should have been. Miss the error in the log and you print a list studded with triple exclamation marks.

The fix is the one the error names: pass the level count as a numeric package option. \usepackage[sharp,14]{easylist} carried the same source through cleanly, printing all the way to 1.1.1.1.1.1.1.1.1.1.1.1.1.1. with no error. Any number works, but the counters are allocated at load time, so it is polite to ask for only what you need. And if you genuinely have a list more than ten levels deep, the obvious advice also applies: the structure of the document is probably the thing to question.

From tractatus to itemize: the six built-in presets

easylist ships six presets, named in the environment's optional argument as \begin{easylist}[tractatus]. They are tractatus, checklist, booktoc, articletoc, enumerate and itemize, defined around line 820 of easylist.sty. The first of them is, as the name says, the numbering system of Wittgenstein's *Tractatus Logico-Philosophicus*. Set it and you get 1. 1.1 1.11 1.2 2.: a period only after the first level, and below that the digits simply run on. The table of contents of that 1921 book comes back to you from a single word of option.

PresetWhat it printsWhere it fits
tractatus1. 1.1 1.11 1.2 2.Philosophy and logic, where propositions nest
checklistHides the numbers and puts an empty square before each itemChecklists meant to be ticked by hand
booktocLevel 1 large and bold with uppercase roman numerals, deeper levels indentedHand-built tables of contents
articletocA lighter booktoc: level 1 bold, no period after the numberArticle-scale contents lists
enumerate1. then (a) then i. then A.Going deep while looking exactly like standard enumerate
itemize then then then ·Unnumbered bullets, imitating the standard marks

Two of them, enumerate and itemize, deliberately imitate the look of the standard lists. Measured, the first prints 1. (a) i. A. and the second ·. But the itemize preset does not use the real label commands such as \labelitemi; it hand-rolls approximations out of \textbullet, --, $\ast$ and $\cdot$ (lines 858–864 of easylist.sty). How the standard marks are actually defined is measured on the custom-labels page, which is the place to go if you want to change the marks themselves. What easylist adds is that you can keep that look and carry on into levels five and six.

Setting numbers and indentation with \ListProperties

Where a preset falls short, \ListProperties(...) fixes it. You write key=value pairs separated by commas inside the parentheses, and the settings apply to every item and list that follows. Many keys have a per-level form made by appending the level number: Numbers for all levels, Numbers3 for level 3 only. \NewList puts everything back to the defaults. Note that \ListProperties is not required — easylist works with none of it, as the first example on this page shows. Settings are only for when you want the look changed.

KeyWhat it doesExample
NumbersNumber style: a arabic (default), r/R lower/upper roman, l/L lower/upper letters, z Zapf DingbatsNumbers2=R, Numbers3=l
Mark / FinalMarkSeparator between counters (a period by default) and the mark after the last oneFinalMark= removes the trailing period
StyleTypeface; * targets the number only, ** the body text onlyStyle1*=\bfseries bolds only the level-1 numbers; \color{blue} works too
HideHide the first n counters, which is how you get an unnumbered listHide=10000 hides the numbers at every level
StartCounter start value; the * form ties it to an external counterStart1*=\thesection follows the section number
ProgressiveLeft margin grows with depth; the * form keeps level 1 at the current marginProgressive=1.5em
SpaceVertical space between items; the * form is between items at the same level. Negative values tighten itSpace*=2pt
document.tex
\documentclass{article}
\usepackage[sharp]{easylist}
\begin{document}
\ListProperties(Style1*=\bfseries, Numbers2=R, Numbers3=l,
  Progressive=1.5em, Space*=2pt)
\begin{easylist}
# Agreement.
## Definitions.
### Party means a signatory hereto.
### Effective Date means the date of last signature.
## Term and termination.
### This Agreement begins on the Effective Date.
#### Either party may terminate on 30 days notice.
##### Notice must be given in writing.
# Miscellaneous.
\end{easylist}
\end{document}

Here level 1 prints bold arabic numerals, level 2 uppercase roman and level 3 lowercase letters, composing as 1.I.a.. Levels 4 and 5 appear simply by writing #### and ##### , each indented a further 1.5em by Progressive. Other keys handle the fine adjustments: Hang (hang the text off the number), Align (line up items at the same level), Margin and Indent (left margin and paragraph indent), FinalSpace (gap between number and text, .3em by default) and CtrCom (wrap the whole number in something like \fbox). To put a literal comma or closing parenthesis into a value, brace it: \ListProperties(FinalMark={)}).

#, @ or &: which marker to choose, and which one wrecks tables

The marker is chosen by package option: nothing gives the section sign §, [pilcrow] gives , [sharp] gives #, [at] gives @, and [ampersand] gives &. The one character you choose becomes an active character between \begin{easylist} and \end{easylist} and reverts outside. The widely repeated advice here — that # is LaTeX's parameter character and so clashes inside tables, and that switching to & is the safe move — turned out, when measured, to be backwards.

Putting a tabular inside an easylist environment on TeX Live 2024, [sharp] went through without complaint; a macro defined outside the environment can also be called inside it as usual. Do the same with [ampersand], however, and the & is eaten as an item marker rather than a column separator: ! Missing } inserted., ! Missing \cr inserted. and ! Missing { inserted. cascade, and the table cells turn into list items two, three and four. For a list containing tables, & is the worst possible choice. What actually breaks # is defining a new macro inside the environment. Put \newcommand\inside[1]{[#1]} just before # \inside{boom} and the #1 is read as a marker, the definition never happens, and you get ! Undefined control sequence. Define macros outside the environment, or switch the marker off temporarily with \Activate and \Deactivate inside the list.

OptionMarkerMeasured behaviour
(none)§ (section sign, the default)Awkward to type; that is its only real drawback
pilcrow (pilcrow)Behaves like §, and is just as awkward to type
sharp#Survives inside tabular, but no macro definitions inside the environment. \# still prints a literal one
at@In a beamer frame it printed the @ literally with no numbering. Avoid in documents whose prose contains @
ampersand&Catastrophic in a list containing tabular: ! Missing \cr inserted. and the table becomes list items

Numbers vanish in beamer: what happens without [fragile]

To use easylist on a beamer slide, mark the frame [fragile]. With it, both [sharp] and [at] numbered the items as expected. Without it the two markers fail in completely different ways. [sharp] fails loudly, emitting ! Illegal parameter number in definition of \iterate. and a ! You can't use ... complaining that the macro parameter character is not allowed in internal vertical mode, while the items collapse onto one line. [at] is the nastier case: exit status 0, not a single error, and yet the PDF carried @ One. @@ Two. with the markers printed as ordinary text. The silent failure is the one that bites later.

beamer
\documentclass{beamer}
\usepackage[sharp]{easylist}
\begin{document}
% [fragile] is required: without it the markers are tokenised before
% easylist has a chance to make them active.
\begin{frame}[fragile]{Nested points}
\begin{easylist}
# First point.
## Supporting detail.
\end{easylist}
\end{frame}
\end{document}

The other common worry is whether it clashes with enumitem. It does not. On TeX Live 2024, loading enumitem before or after easylist both compiled without a single error, and an easylist list happily coexisted with \begin{itemize}[label=\textbullet] in the same document. Their jobs do not overlap: enumitem reshapes the appearance of itemize and enumerate through key-value options, while easylist adds a separate environment alongside them. Having both loaded causes no trouble, at least at load time.

easylist or enumitem: which to reach for

One question settles it: is the depth part of the structure of the document, or just a matter of appearance? For contract clauses, standards, statutes and finely branching outlines — text where five and six levels carry meaning — easylist is the answer. Adding one # goes one level deeper, and not having to keep \begin and \end balanced in your head is a real relief once you are actually typing a long set of clauses. If instead your lists stop at two or three levels and what you want is fine control over number formats, spacing, inline lists and label substitution, enumitem is the right place. It owns the key-value approach, and easylist's \ListProperties is no substitute for it.

One last point. Standard itemize and enumerate keep separate depth counters, so alternating between them nests six levels deep — a fact measured on the custom-labels page. The famous four-level wall is therefore lower than it looks. easylist still earns its place past six levels, or on the day you tire of counting environment pairs. It is by Paul Isambert; the version in TeX Live 2024 is v1.4, dated 11 January 2014, under the LPPL. A package that has not moved in a decade — but one that does few enough things to have few places left to break.