117

Is it possible to split an itemize list into several columns? (I'm sure it is, but I couldn't find a solution around here)

And additionally: Is it possible to automatically split a list into multiple columns if it reaches a certain item length?

For example, I want to display

item1
item2
item3

instead of

item1   item2   item3

while this should still happen:

item1   item4
item2   item5
item3   item6
4

6 Answers 6

33

Here is some code that does the automatic column adjust thing, I used the code found in "count and use the number of items in advance" to help me.

\documentclass{article}
\usepackage{etoolbox,refcount}
\usepackage{multicol}

\newcounter{countitems}
\newcounter{nextitemizecount}
\newcommand{\setupcountitems}{%
  \stepcounter{nextitemizecount}%
  \setcounter{countitems}{0}%
  \preto\item{\stepcounter{countitems}}%
}
\makeatletter
\newcommand{\computecountitems}{%
  \edef\@currentlabel{\number\c@countitems}%
  \label{countitems@\number\numexpr\value{nextitemizecount}-1\relax}%
}
\newcommand{\nextitemizecount}{%
  \getrefnumber{countitems@\number\c@nextitemizecount}%
}
\newcommand{\previtemizecount}{%
  \getrefnumber{countitems@\number\numexpr\value{nextitemizecount}-1\relax}%
}
\makeatother    
\newenvironment{AutoMultiColItemize}{%
\ifnumcomp{\nextitemizecount}{>}{3}{\begin{multicols}{2}}{}%
\setupcountitems\begin{itemize}}%
{\end{itemize}%
\unskip\computecountitems\ifnumcomp{\previtemizecount}{>}{3}{\end{multicols}}{}}

\begin{document}

\begin{itemize}
    \item Here are two columns
  \begin{AutoMultiColItemize}
  \item Item 1
  \item Item 2
  \item Item 3
  \item Item 4
  \item Item 5
  \item Item 6
  \end{AutoMultiColItemize}
  \item AutoMultiColItemize can be nested in an itemize
  \item Or it does not have to be.
  \item Normal itemize, like this one, are still single column.
\end{itemize}
Here is one column
\begin{AutoMultiColItemize}
\item Item 1
\item Item 2
\item Item 3
\end{AutoMultiColItemize}

\end{document}

Here is what it looks like: Multiple Columns

6
  • 3
    Thanks a lot for this great solution! This makes documents with many lists definitely cleaner. As a Tex beginner, all this stuff is a new world to discover and I love it how fast one can get perfect help around the stackexchange network. Awesome Stackexchange folks =)!
    – Daniel
    Aug 2, 2014 at 23:53
  • Great effort Strategy Thinker. Still one problem though, the items are not vertically aligned. Items of the right column are closer!! It becomes clearer if you add Item 4 in the last list.
    – AboAmmar
    Aug 3, 2014 at 0:26
  • Thanks, I needed to add a \unskip after \end{itemize}, otherwise it would create a new line. Aug 3, 2014 at 16:38
  • The image illustrating the result doesn't exist anymore.
    – usernumber
    Oct 25, 2017 at 18:39
  • @usernumber I restored that image using the wayback machine on web.archive.org
    – Daniel
    Nov 1, 2017 at 12:43
214

Since you want multiple columns, you should use the multicol package:

enter image description here

Code:

\documentclass{article}
\usepackage{multicol}

\begin{document}
Two columns:
    \begin{multicols}{2}
    \begin{itemize}
        \item item 1
        \item item 2
        \item item 3
        \item item 4
        \item item 5
        \item item 6
    \end{itemize}
    \end{multicols}
    
Three columns:
    \begin{multicols}{3}
    \begin{itemize}
        \item item 1
        \item item 2
        \item item 3
        \item item 4
        \item item 5
        \item item 6
    \end{itemize}
    \end{multicols}
\end{document}
4
  • What can happen if you have an item with long text? Sure it will extend to the next column. What is the solution in this case?
    – AboAmmar
    Aug 2, 2014 at 21:48
  • 1
    @AboAmmar: I am not sure I fully understand the problem you are describing. Please edit your question and provide a test case (MWE) that illustrates what you are describing and what you think the "correct" output should be. Aug 3, 2014 at 4:16
  • 16
    as much as it pains me to say, but multicol is not a good solution to this problem in a general case. It works alright in your examples above, because they all contain single line items and the same in each column, but this gets bad the moment you have different amounts of text per column. As multicol starts with slighly compressed column heights and works its way up to the point they balance you normally end up with uneven (and compressed glue and that can look rather horrible. See my talk from Tokyo 2013 (latex-project.org/papers) where I discuss some of those issues. Aug 5, 2014 at 19:32
  • 6
    (for the lazy, the slides from the 2013 talk are at latex-project.org/publications/2013-10-23-FMi-stony-beamer.pdf). Any progress since this talk on that question, @FrankMittelbach ?
    – Clément
    Feb 2, 2019 at 19:39
32

Use multicol. If your items do not divide evenly into each column, add \item[\vspace{\fill}] to the end of your list to align the items.


The multicol package solution from AboAmmar works well if your enumerate items can be divided evenly into each column.

However, spacing between items can become inconsistent if each column does not hold an equal number of items. For example, dividing 7 items between 2 columns:

One can fix this easily by adding an 'empty' item at the end of the list as padding.

\item[\vspace{\fill}]

Which produces the following nicely aligned multi-columned enumerate list:

enter image description here

\documentclass[preview]{standalone}
\usepackage{multicol}
\begin{document}

\begin{multicols}{2}
  \begin{enumerate}
    \item one  \item two \item three \item four
    \item five \item six \item seven \item[\vspace{\fill}]
  \end{enumerate}
\end{multicols}

\end{document}
1
  • A very useful answer, especially about the spacing bit. But, suppose the items are multiline, and differenly so, is there a way one can cause 1 to align with 5, 2 with 6, and so on so that each line across from one another always start on the same line of text? (for reference, I have two separate enumerate envs, so they both number the same, so its really 1 to 1, 2 to 2, etc)
    – hanetzer
    Jan 6, 2023 at 22:10
11

A quick possible solution is using the minipage environment as follows:

\documentclass[12pt,a4paper]{article}
\begin{document}

\begin{itemize}
\begin{minipage}{0.4\linewidth}
    \item item 1
    \item item 2
    \item item 3
\end{minipage}
\begin{minipage}{0.4\linewidth}
    \item item 4
    \item item 5
    \item item 6
\end{minipage}
\end{itemize}

\end{document}

This outputs:

enter image description here

5
  • I would note that this quickly becomes unmaintainable and doesn't purely represent the idea of columns. Aug 2, 2014 at 22:15
  • @Sean Allred- However, using two minipages will change how list items are numbered (column-wise rather than row-wise, as desired). Only the second part of the question hasn't been answered. None of the other 3 answers succeeded in this regard.
    – AboAmmar
    Aug 3, 2014 at 0:00
  • Try it with enumerate instead. Aug 3, 2014 at 0:00
  • Good point about the desired behavior though; you're right in that multicol will always use as little vertical space as possible. Perhaps a better question to ask, in this case, is if it is possible to give the multicols environment a minimum vertical space to occupy. Edit: I spoke too soon; see the accepted answer :) Aug 3, 2014 at 0:10
  • I didn't know you could have a minipage inside itemize... it didn't work for me (beamer class), but of course having itemize inside minipages worked fine.
    – PatrickT
    Nov 26, 2017 at 11:46
4

For the first question, you can do that with the tasks package, that was formerly part of the exsheets bundle. If you use MiKTeX, beware it requires the cntformats package (from the same author), that's not (yet) part of MiKTeX. To answer Werner's question, it can break across pages.Here is an example of how it works:

\documentclass[twoside, a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[x11names]{xcolor}
\usepackage{fourier}
\usepackage[noheadfoot, nomarginpar, showframe]{geometry}

\usepackage{tasks}
 \DeclareInstance{tasks}{myitemize}{default}
 {
enumerate = false ,
label-width = 1.125em,
label-offset = 0.6em,
label-format = \bfseries\color{IndianRed3}
 }

\settasks{style = myitemize, column-sep = 2em}%
\pagestyle{plain}%


\begin{document}

\begin{tasks}(3)
    \task First item
    \task A second item
    \task A third one
    \task A second series, item 1
    \task Second series, item 2
    \task Second series, item 3
\end{tasks}

\end{document} 

enter image description here

Another solution would use the shortlst package, which is not part of any distribution for license reasons, so that you have to install it yourself. I patched it so as to be able to choose the number of columns with a key nc=value (3 by default) and the interline stretch il=value (1.33 by default).

The main advantage of this package is that if an item is longer than the column width it automatically spreads over two (or more) columns. Alternatively an item can be put in a parbox of width column width. I introduced a \paritem command, that takes as an optional argument the number of columns the item will spread over.

\documentclass[twoside, a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[x11names]{xcolor}
\usepackage{fourier}
\usepackage[nohead, nomarginpar, showframe]{geometry}

\pagestyle{plain}%

\usepackage{ragged2e}

\usepackage{shortlst, setspace, xkeyval}

\makeatletter
\newcounter{ncol}
\define@key{lex}{nc}[3]{\setcounter{ncol}{#1}}%% 3 columns by default
\define@key{lex}{il}[1.33]{\def\@intln{#1}}% interlining![1]
\newenvironment{tabitemize}[1][]{%
\setkeys{lex}{nc,il,#1}
\settowidth{\labelwidth}{\quad\textbullet}
\setlength{\leftmargini}{\dimexpr\labelwidth+\labelsep\relax}%[1][3]
\setlength{\shortitemwidth}{\dimexpr\linewidth/\value{ncol}-\labelwidth-2\labelsep\relax}%
\renewcommand{\labelitemi}{\textcolor{Tomato3}{\bfseries\textbullet}}
\setstretch{\@intln}
\begin{shortitemize}}%
{\end{shortitemize}
 }%
 \newcommand\paritem[2][2]{\item \parbox[t]{\dimexpr#1\shortitemwidth + (2\labelsep + \labelwidth)*\numexpr#1-1\relax}{\setstretch{1}#2}}
\makeatother
\usepackage{lipsum} 

\begin{document}
\vspace*{1 cm}

\begin{tabitemize}
    \item First item
    \item A second, much longer item
    \item A third, short item
    \paritem[2]{A second series, with a much longer item. \lipsum[2]}%
    \item Second series, item 4\strut
    \item Second series, third item, a much much longer item\strut
    \item Second series, fourthr item\strut
\end{tabitemize}

\end{document} 

enter image description here

3
  • While I like the tasks package (obviously) it does not do what the OP wants: items are arranged per row instead of per column. (BTW: items cannot contain page breaks)
    – cgnieder
    Aug 2, 2014 at 20:08
  • Oh! Sorry. I misread, due to the fact the solutions are better known in that case. Should I withdraw my answer?
    – Bernard
    Aug 2, 2014 at 20:56
  • 3
    No, I'm sure it'll be useful for people.
    – cgnieder
    Aug 2, 2014 at 20:57
0

Here is javascript code for TeXstudio macro that can do from this

One, two, three,
B is for bee. One, two,
The bee is near you. 

automatically to this (multicol package is required)

\begin{enumerate}
    \begin{multicols}{3}
        \item One, two, three,
        \item B is for bee. One, two,
        \item The bee is near you.
    \end{multicols}
\end{enumerate} 

Maximal number of columns and enviroment (enumerate or itemize) can be chosen by colmax and type variables.

%SCRIPT
var colmax = 4; //maximal number of columns
var type = 0; //0 for enumerate, 1 for itemize
var lt, c, d, n, out;
var txt = cursor.selectedText();
if (type == 0) lt = 'enumerate';
else lt = 'itemize';
function srch(re, str) {
       if (str.search(re) != -1)
          return 1;
       else
          return 0;}
var itarr = [srch(/enumerate/g, txt), srch(/itemize/g, txt), srch(/item/g, txt)]
var sum = itarr.reduce(add, 0);
function add(a, b) {return a + b;}
if (sum == 2)
    c = 2, d = 2;
    else if (sum == 1)
        c = 1, d = 0;   
    else {
        c = 0, d = 0;
        txt=txt.replace(/\n/g, '\n\\item ');}
txt.replace('\t','');
n = txt.split('\n').length-d;
for (n; n>colmax; n = 0.5*n);
n = Math.round(n);
cursor.removeSelectedText();
var p = ['\\begin{'+lt+'}\n', '\\begin{multicols}{'+n+'}\n', '\\item ', txt, '\n\\end{multicols}', '\n\\end{'+lt+'}'];
if (c == 2) out = [p[1], p[3], p[4]];
else if (c == 1) out = [p[0], p[1], p[3], p[4], p[5]];
else out = p;
editor.write(out.join(''));
3
  • 1
    Welcome to TeX.SX! It seems like your answer uses code from another language besides LaTeX - could you indicate what it is and what part of the LaTeX code it produces? Jun 17, 2016 at 18:30
  • It's written on javascript, i've edited my post. Latex examples inserted at the top. Is it ok? Jun 17, 2016 at 20:39
  • Yes, looks good (I wasn't aware TeXstudio could read JavaScript macros! But now I know). However, it seems your answer has the same problem as Peter's, namely distributing everything across 3 columns, whereas OP wanted to fill out one column before starting the next. Jun 17, 2016 at 21:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .