23

How do I create a description list where the item text is automatically indented to the width of the widest label?

This is the same question as Description list with aligned descriptions but I would like the width of the widest label to be automatically calculated.

For example, I'd like the following output:

example output

to be produced by the following input:

\documentclass{article}
\usepackage{calc}
\usepackage{enumitem}
\usepackage{lipsum}
\usepackage[margin=1em,papersize={4in,2.2in}]{geometry}

\newenvironment{mydescription}{%
  \begin{description}[
    leftmargin=!,
    labelwidth=\magicgoeshere,
    ]%
}{%
  \end{description}%
}

\newcommand{\text}{long long long long long long long long long long
  long long long long long long long long long long long long long
  long long long long long long long text}

\begin{document}
\begin{mydescription}
\item[The longest label] text
\item[Short] \text
\end{mydescription}
\hrule
\begin{mydescription}
\item[Medium label] text
\item[Short] \text
\end{mydescription}
\end{document}
23

A variation on egreg's answer to Working with margins

\documentclass{article}
\usepackage{enumitem}
\usepackage{environ}

\newlength\widest
\makeatletter
\NewEnviron{ldescription}{%
  \vbox{%
    \global\setlength\widest{0pt}%
    \def\item[##1]{%
      \settowidth\@tempdima{\textbf{##1}}%
      \ifdim\@tempdima>\widest\global\setlength\widest{\@tempdima}\fi%
    }%
    \setbox0=\hbox{\BODY}%
  }
  \begin{description}[
    leftmargin=\dimexpr\widest+0.5em\relax,
    labelindent=0pt,
    labelwidth=\widest]
  \BODY
  \end{description}%
}
\makeatother

\begin{document}

\begin{ldescription}
\item[Short] text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
\item[A really really long label] text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
\end{ldescription}

\begin{ldescription}
\item[Short] text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
\item[A medium label] text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
\end{ldescription}

\end{document}

enter image description here

In the first part, the width of the longest label is calculated: initially, \widest is set to 0pt; for each \item, the length of its optional argument is measured and the length stored in \@tempdima; if \@tempdima is greater than \widest, (this is always true for the first \item) then \widest is updated to be \@tempdima. This is done for all \items; \BODY is set inside a box that is never used. Then, a description environment is used, setting \labelwidth to the previously calculated value for \widest.

Answers to follow-up questions:

  • Q: What is the point of \setbox0=\hbox{\BODY}?
    A: This just boxes \BODY without typesetting it.
  • Q: Since \BODY is used twice, what happens if \BODY contains something that has side effects (writes to the .aux file, contains \newcommand, contains \footnote, etc.)?
    A: There's no problem with what \BODY contains (as long as it's reasonable for a standard description, so, for example, sectional unit commands won't be allowed, but they don't make sense in a description anyways).
  • Q: Why is that stuff wrapped in a \vbox{}?
    A: The \vbox is used to prevent the dreadful "Something's wrong--perhaps a missing \item." error at the beginning of a list (\hbox or \mbox could have also been used instead).
  • Thanks! Can you explain how this works? I thought I would have to somehow save the widest length to the .aux file and reuse it in a second pass, but your example shows that this is not necessary. I'm not sure how you do it without requiring a second pass. – Richard Hansen Aug 25 '13 at 23:47
  • @RichardHansen I added a short explanation at the end of my updated answer. – Gonzalo Medina Aug 26 '13 at 0:39
  • Thanks for updating it, but I still have some questions: Why is that stuff wrapped in a \vbox{}? What is the point of \setbox0=\hbox{\BODY}? Doesn't redefining \item affect spacing and \label? Since \BODY is used twice, what happens if \BODY contains something that has side effects (writes to the .aux file, contains \newcommand, contains \footnote, etc.)? – Richard Hansen Aug 26 '13 at 4:40
  • @RichardHansen For some reason I didn't receive the notification of your last comment, so I just casually saw it. \setbox0=\hbox{\BODY} just boxes \BODY without typesetting it. There's no problem with what \BODY contains (as long as it's reasonable for a standerd descrition, so, for example, sectional unit commands won't be allowed, but they don't make sense in a description anyways). The \vbox is used to prevent the dreadful "Something's wrong--perhaps a missing \item." error at the beginning of a list (\hbox or \mbox could have also been used instead). – Gonzalo Medina Aug 27 '13 at 0:51
  • @RichardHansen Just a Hint : It would be advisable to ask GonzaloMedina to add his explanation from comments to answer by pinging him so that he would make the answer flow continuous and smooth. – texenthusiast Aug 27 '13 at 4:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.