# Creating lists with items separated by a rule

How can I create a list in which a rule is automatically inserted between each pair of items?

-

2014-07-23: Updated to support optional parameter of \item.

An alternate method that you can use is to redefine \item. This is not necessarily a better solution in this case, but you don't need to rely on the internals of other packages. I use a modified version of the rule that @Werner defined in his solution, but that can be adjusted as desired.

Here I use etoolbox to handle the condition that we do not want to apply the rule above the very first \item. I prefer this method of handling conditions, but any other method for Conditional typesetting / build can be used as well.

First step is to save the original definition of item

\LetLtxMacro{\OriginalItem}{\item}%


As we are redefining a macro with optional parameters, we use \LetLtxMacro from the letltxmacro package . A detailed description of \LetLtxMacro can be found at this question at closed square root symbol.

Now using this we can define our own version of item:

\newcommand{\ItemWithRuleAbove}[1][]{%
\iftoggle{IsFirstItem}{}{\WernersHRule}% only add \hrule if not first item
\IfStrEq{#1}{}{\OriginalItem }{\OriginalItem [#1]}%
\togglefalse{IsFirstItem}%
}%


where:

1. if this is not the first item, we add the rule,
2. apply the original definition of item, and
3. toggle the IsFirstItem so that we know for next time that a rule is to be applied.

Using this definition we can create our own MyEnuterate environment that has this behaviour (assuming you don't want this all the time):

\newenvironment{MyEnumerate}{%
\toggletrue{IsFirstItem}%
\let\item\ItemWithRuleAbove%
\begin{enumerate}%
}{%
\end{enumerate}%
}%


within this environment we redefine \item to use \ItemWithRuleAbove as opposed to the original \item. At the beginning of this environment we toggle IsFirstItem to true so that it is initialized for this instance of MyEnumerate.

## Code:

Enumerated content copied directly from @Werner's solution:

\documentclass{article}
\usepackage{etoolbox}
\usepackage{xstring}
\usepackage{letltxmacro}

\newtoggle{IsFirstItem}% so we don't add rule above first item
\toggletrue{IsFirstItem}% personal preference: initialize variables explicetly at time of defintion

\newcommand*{\WernersHRule}{% Slightly Modified
\par\kern\dimexpr.7\itemsep-\parskip-.6\baselineskip\relax%
\hrulefill%
\par\kern\dimexpr.3\itemsep-.3\parskip-.6\baselineskip\relax%
}%

\LetLtxMacro{\OriginalItem}{\item}% store existing definition of \item
\newcommand{\ItemWithRuleAbove}[1][]{%
\iftoggle{IsFirstItem}{}{\WernersHRule}% only add \hrule if not first item
\IfStrEq{#1}{}{\OriginalItem }{\OriginalItem [#1]}%
\togglefalse{IsFirstItem}%
}%

\newenvironment{MyEnumerate}{%
\toggletrue{IsFirstItem}%
\let\item\ItemWithRuleAbove%
\begin{enumerate}%
}{%
\end{enumerate}%
}%

\begin{document}
\begin{minipage}{.45\linewidth}
\begin{MyEnumerate}
\item An item with descender p
\item[a.] An item without descenders
\item abcdefghijklmnopqrstuvwxyz
\end{MyEnumerate}
\end{minipage}
%
\begin{minipage}{.45\linewidth}
\begin{enumerate}
\item An item with descender p
\item[a.]  An item without descenders
\item abcdefghijklmnopqrstuvwxyz
\end{enumerate}
\end{minipage}
\end{document}

-
Hi! I tried to use your solution for creating new description-like environment but didn't succeed (parameter for \item command is treated literally, but not as a parameter). Would you add solution for this to your answer? Or should I create new question? –  Artem Pelenitsyn Jul 23 '14 at 6:47
@ArtemPelenitsyn: Have updated solution to properly handle optional parameters of \item. –  Peter Grill Jul 23 '14 at 16:11
that's great, thank you very much! –  Artem Pelenitsyn Jul 24 '14 at 9:12

The standard list structures (itemize and enumerate) is made up as a \list. At the start of this \list, a condition \@newlist is set to true (via \global\@newlisttrue). This separates the first item from the rest in terms of the vertical space inserted. Here's an extract from the conditioning within \@item in latex.ltx:

\if@newlist
\if@nobreak
\@nbitem
\else
\fi
\else
\fi


So, based on this, \itemsep is only inserted if we're not \@newlist.

Using etoolbox one can now patch \@item and modify \addvspace\itemsep to insert a "decoration":

\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/xpatch
\begin{document}
\noindent%
\begin{minipage}{.45\linewidth}
\begin{enumerate}
\item An item with descender p
\item An item without descenders
\item abcdefghijklmnopqrstuvwxyz
\end{enumerate}
\end{minipage}
%
\makeatletter
\patchcmd{\@item}
{\par\kern\dimexpr.7\itemsep-.7\parskip-.7\baselineskip\relax%
\hrulefill%
\par\kern\dimexpr.3\itemsep-.3\parskip-.3\baselineskip\relax}
{}{}%
\makeatother
%
\begin{minipage}{.45\linewidth}
\begin{enumerate}
\item An item with descender p
\item An item without descenders
\item abcdefghijklmnopqrstuvwxyz
\end{enumerate}
\end{minipage}
\end{document}


On the left is a regular list, while the right shows the same list with the modified \itemsep.

If you want the \hrulefill to stretch the entire \textwidth (rather than \linewidth), you can use

\makeatletter
\patchcmd{\@item}

which corrects for the \itemindent, \labelwidth and \labelsep inserted in the list.
The choice of a 70%/30% skip across the horizontal rule is somewhat arbitrary, but based on the definition of \strutbox. Together, they make up the entire \itemsep.
nice approach. But I would keep the \addvspace. After all, if the previous item ended in a vertical skip for some reason you want the maxium of both skips not the addition. So perhaps start the patch code with \addvspace\itemsep\vskip-\itemsep followed by your code. Also using \kernmeans you are dropping stretch and shrink and "perhaps" one would like to retain that at least above the rule. –  Frank Mittelbach Feb 11 '12 at 17:43