The itemize package allows users to easily customize and format enums and lists. To use this package, include the following at the beginning of your document:
#import "@preview/itemize:0.2.0" as el
Use the method default-enum-list to override the native behavior of enum and list by adding the following at the beginning of your document:
#show: el.default-enum-list
Now you can use enum and list as usual. Below is a comparison.

Code:
#let item-test = [
+ one $vec(1, 1, 1)$
$
x^2 + y^2 = z^2
$
+ #rect(height: 2em, width: 2em) #lorem(2)
+ #block(stroke: 1pt)[two $vec(1, 1, 1,)$]
+ $ (a + b)^2 = a^2 + 2a b + b^2 $
+ + #lorem(2)
+ - #lorem(2)
- #lorem(2)
]
#table(
columns: (1fr, 1fr),
[native], [itemize],
[
#item-test
],
[
#show: el.default-enum-list
#item-test
],
)
See manual.pdf and also the source code manual.typ for more details.
Examples
Click on the example image to jump to the code.
Features
The itemize package currently offers the following features:
- Compatibility with native
enumandlistbehaviors in most cases, along with fixes for certain native bugs (or providing alternative choices), such astypst/issue#1204andtypst/issue#529. - Provide two styles of enum-list:
defaultandParagraph - Customization of
enumandlistlabels and bodies by level and item:- Horizontal spacing settings:
indent,body-indent,label-indent,enum-margin(is-full-width). - Vertical spacing settings:
item-spacing,enum-spacing. - Label formatting settings:
..args(text-style),label-align,label-baseline,label-width.- Customize labels in any way:
label-format.
- Customize labels in any way:
- Alignment styles for labels between items at each level:
auto-label-width. - Body formatting settings:
hanging-indent,line-indent.- Set text and border styles for the body:
body-format.
- Set text and border styles for the body:
- Horizontal spacing settings:
- Enhanced
enumfeatures:- Reference functionality for
enumnumbering. - Resume functionality for
enumnumbering.
- Reference functionality for
- Enhanced
listfeatures:- Terms-like functionality: Temporarily change the marker of the current item using the
itemmethod. - Checklist functionality (similar to the
cheqpackage).
- Terms-like functionality: Temporarily change the marker of the current item using the
The package itemize primarily provides the following methods:
Two Styles of enum-list
default-style (Typst’s native style):default-enum-list,default-enum,default-listparagraph-style:paragraph-enum-list,paragraph-enum,paragraph-list
By default, the default-* methods indent paragraphs after the label, while the paragraph-* methods align paragraphs with the label. See the example below:

Code:
#let test = [
+ #lorem(10)
#lorem(10)
+ #lorem(10)
#lorem(10)
+ #lorem(10)
+ #lorem(10)
- #lorem(10)
- #lorem(10)
+ - + - #lorem(10)
]
#table(
columns: (1fr, 1fr),
[
default-style
```typ
#set enum(numbering: "(A).(I).(i)")
#show: el.default-enum-list
```
],
[
paragraph-style
```typ
#set enum(numbering: "(A).(I).(i)")
#show: el.paragraph-enum-list
```
],
[
#set enum(numbering: "(A).(I).(i)")
#show: el.default-enum-list.with(auto-base-level: true)
#test
],
[
#set enum(numbering: "(A).(I).(i)")
#show: el.paragraph-enum-list.with(auto-base-level: true)
#test
],
)
The differences between *-enum-list, *-enum, and *-list are:
*-enum-listcan uniformly configure bothenumandlist, while allowing separate configuration through parameters:enum-configforenumlist-configforlist
*-enumonly configuresenum, leaving nestedliststyles unchanged*-listonly configureslist, leaving nestedenumstyles unchanged
Enum Numbering References
To enable this feature, add the following at the beginning of your document:
#show: el.config.ref
The
ref-enummethod from ver0.1.x will be deprecated in the future. Please useconfig.reffor this configuration.
In the enum items you want to reference, label them with <some-label>, and then use @some-label to reference the enum number of that item.
Example (taken from: https://github.com/typst/typst/issues/779#issuecomment-2702268234)

Code:
#show: el.config.ref.with(supplement: "Item")
#show link: set text(fill: orange)
#set enum(numbering: "(E1)", full: true)
#show: el.default-enum-list
Group axioms:
+ Associativity <ax:ass>
+ Existence of identity element <ax:id>
+ Existence of inverse element <ax:inv>
#set enum(numbering: "1.a", full: true)
#set math.equation(numbering: "(1.1)")
Another important list:
+ Newton's laws of motion are three physical laws that relate the motion of an object to the forces acting on it.
+ A body remains at rest, or in motion at a constant speed in a straight line, unless it is acted upon by a force.
+ The net force on a body is equal to the body's acceleration multiplied by its mass.
+ If two bodies exert forces on each other, these forces have the same magnitude but opposite directions. <newton-third>
+ Another important force is hooks law: <hook1>
$ arrow(F) = -k arrow(Delta x). $ <eq:hook> #el.elabel[hook2]
+ $F = m a$ <eq:c> #el.elabel("eq:ma")
We covered the three group axioms @ax:ass[], @ax:id[] and @ax:inv[].
It is important to remember Newton's third law @newton-third[], and Hook's law @hook1. In @hook2 we gave Hook's law in @eq:hook. Note that @eq:ma[Conclusion] is a simplified version.
For the label
<hook2>, you cannot directly write<hook2>, as this would label<hook2>to the equation. Use the methodelabelto label it. The same applies toeq:c.
The method
elabel(<some-label>)is equivalent toelabel("some-label"), and can sometimes be written aselabel[some-label](provided the latter can be parsed as a string).
Resuming Enum Numbering
-
To enable this feature, set the
auto-resumingparameter toautoin*-enum-list(or*-enum). -
Use the
resume()method to continue numbering from the previous ones.#show: el.default-enum-list.with(auto-resuming: auto) + #lorem(5) + #lorem(5) + #lorem(5) #lorem(5) + #lorem(5) #el.resume() // -> 3 + #lorem(5) + #lorem(5) + #lorem(5) + + #lorem(5)
-
Alternatively, use
resume-label(<some-label>)to label the enum to resume, then useresume-list(<some-label>)in the desired enum to continue numbering.-
If the following is added to the document:
#show: el.config.ref-resumeYou can use
@some-labelinstead ofresume-list(<some-label>).
#show: el.config.ref-resume #let auto-resume = el.default-enum-list.with(auto-resuming: auto) #auto-resume[ + #lorem(5) + #lorem(5) + #lorem(5) - #lorem(5) #el.resume() // continue + #lorem(5) #el.resume-label(<resume:demo>) #lorem(5) @resume:demo // resume the enum labelled with `resume:demo` + #lorem(5) ]
-
-
Alternatively, use
auto-resume-enum(auto-resuming: true)[...]to ensure allenumitems within[...]continue numbering from the previous items. For example:#let resume-enum(doc) = el.default-enum-list(auto-resuming: auto)[ #el.auto-resume-enum(auto-resuming: true, doc) ] #resume-enum[ + #lorem(5) + #lorem(5) + #lorem(5) + #lorem(5) - #lorem(5) + #lorem(5) + #lorem(5) #lorem(5) + #lorem(5) ]
Terms-like Functionality
Now, you can use the item method within a list to temporarily change the marker of the current item. For example:
#show: el.default-enum-list
- #el.item[#sym.ast.square] #lorem(2)
- #el.item[①] #lorem(2)

Checklist
-
To enable this feature, set the
checklistparameter totruein*-enum-list(or*-list), for example:#show: el.default-enum-list.with(checklist: true)Now you can use:
#show: el.default-enum-list.with(checklist: true) - [x] checked #lorem(2) - [ ] unchecked #lorem(2) - [/] incomplete #lorem(2) - [-] canceled #lorem(2)
-
Alternatively, you can enable and configure checklist-related features using the
config.checklistmethod:#show: el.config.checklistExample:
#show: el.config.checklist #show: el.default-enum-list - [x] checked #lorem(2) - [ ] unchecked #lorem(2) - [/] incomplete #lorem(2) - [-] canceled #lorem(2)
The diagram below illustrates the model for enum and list in itemize.
enumandlistconsist of multiple items.- Each item is composed of a
labeland abody:label: The enum number or list marker.body: The content following the label.
- Level (
level): Starts from 1, and increments if an item contains nested items. - Item index (
n): Starts from 1. The position of items in the same level.

The `label-indent` of default-enum-list:

Code Example:
#set align(center)
#set par(justify: true)
#block(width: 80%, stroke: 1pt + red, inset: 5pt)[
#set align(left)
#show: el.default-enum-list.with(
indent: 1em,
label-align: right,
label-width: 3em,
body-indent: 1em,
hanging-indent: 2em,
line-indent: 4em,
is-full-width: false,
enum-margin: 4em,
enum-spacing: 3em,
item-spacing: 2.5em,
)
Preceding Text. #lorem(30)
1. Item 1: Paragraph 1. #lorem(30)
Paragraph 2. #lorem(30)
100. Item 2. #lorem(30)
Following Text. #lorem(30)
]
Output:

*-enum-list Methods
The parameters for default-enum-list and paragraph-enum-list are similar.
-
Horizontal spacing
indent: array | auto | function | length = auto: The indent of enum or list.-
If
indentisauto, the item will be indented by the value ofindentofenumorlist. -
If
indentis anarray, whose elements arelengthorautoorarray, each level of the item will be indented by the corresponding value of the array at positionlevel - 1. The last value of the array will be used for residual levels.- If the last element of the array is
LOOP, the values in the array will be used cyclically. - The elements in the array can also be an array, where each element applies to the corresponding item.
- If the last element of the array is
-
If
indentis afunction, the return value will be used for each level and each item. The function should be declared as:it => length | auto | arrayitis a dictionary that contains the following keys:level: The level of the item.n: The index of the item.n-last: The index of the last item.label-width: The label max-width of the item.label-widthcaptures the label width of items from level 1 to the current level (i.e., [1,level]). Use(label-width.get)(some-level)to get the label width at levelsome-levelorlabel-width.currentfor the current level (equivalent to(label-width.get)(level)).e: captures the construction (enumorlist) of items from level 1 to the current level. Use(level-type.get)(some-level)orlevel-type.current.- If the return value is an
array, it will be used for each item.
-
body-indent: array | auto | function | length = auto: Body indentation value (default: auto), i.e., the space between the label and the body of each item.- If
auto, it uses the value ofbody-indentofenumorlist. - Similar to the
indentparameter.
- If
label-indent: array | auto | function | length = auto: The indentation value for the first line of an item. (default:0emifauto). Similar to theindentparameter.is-full-width: bool = true: Whether to use full width (default: true). This may temporarily fix the bug where block-level equations in the item are not center-aligned in some cases (not an ideal solution).enum-margin: array | auto | function | length = auto: Margin of items for enums and lists (default: auto).- To make
enum-margineffective, setis-full-widthtofalse. - If
auto, the item width isauto. - Similar to
item-spacing.
- To make
-
Vertical spacing
enum-spacing: array | auto | dictionary | length = auto: Spacing between enums and lists (default: auto). Ifauto, it uses the current paragraph spacing or leading (par.spacingorpar.leading), depending on thetightparameter ofenumorlist. Similar toitem-spacing.item-spacing: array | auto | function | length = auto: Spacing between items (default: auto). Ifauto, it uses the value ofspacingofenumorlist. Seeindentfor details.
-
Body style
hanging-indent: array | auto | function | length = auto: The indent for all but the first line of a paragraph (default: auto).- If
auto, it uses the hanging indent of the current paragraph (par.hanging-indent). - Similar to
indent.
- If
line-indent: array | auto | function | length = auto: The indent for the first line of a paragraph excluding the first paragraph (default: auto).- If
auto, it uses the first line indent of current paragraph (par.first-line-indent.amount). - Similar to
indent.
- If
body-format: dictionary | none = none: Sets the text style and border style of the body (default: none). It is a dictionary containing the following keys:none: Does not take effect.style: A dictionary that can include any named arguments oftextto format the text style ofbody.whole,outer,inner: Dictionaries used to set the borders of the item.whole: Wraps the entireenumorlistouter: Wraps the item (including the label)inner: Wraps the item (excluding the label)
- If
whole,outer, orinneris omitted, the default is to set the border forouter. - Supported border properties (consistent with
blockborders):stroke,radius,outset,fill,inset,clip.- ⚠️ In ver0.2.x,
insetwithrelativelength is temporarily not supported!!! - Each value in
style,whole,outer,inneris also supportedarrayandfunctiontypes.
- ⚠️ In ver0.2.x,
-
Label style
..args: arguments: Used to format the text of the numbering. Accepts all named parameters of thetextfunction (e.g.,fill: red,size: 4em,weight: "bold"). Values can bearray,autoorfunction-
If
auto, it uses the currenttextvalue -
If
array, each level uses the corresponding value of the array at positionlevel - 1.- If the last element of the array is
LOOP, the values in the array will be used cyclically, else, - The last value is used for residual levels.
- If the last element of the array is
-
if
function, the return value will be used for each level and each item. The function should be declared as:it => some-value | auto | arrayitis a dictionary that contains the following keys:level: The level of the item.n: The index of the item.n-last: The index of the last item.
-
label-align: array | alignment | auto | function = auto: Thealignmentthat enum numbers and list markers should have.- Unless
autois used, it cannot be be changed via#set enum(number-align: ...). - For native
list, it has no such property.
- Unless
label-baseline: auto | dictionary | function | length | "center" | "top" | "bottom" = auto: An amount to shift the label baseline by.- It can be taken:
length,autoor"center","top","bottom",- or a
dictionarywith the keys:amount:length,autoor"center","top","bottom"same-line-style:"center","top","bottom"alone:bool
- The first case is interpreted as
(amount: len, same-line-style: "bottom", alone: false) - When the label has a paragraph relationship with the first line of text in the current item, the label baseline will shift based on the value of
amount. - For
"center","top", and"bottom", the label will be aligned to the center, top, or bottom respectively. - If labels from different levels appear on the same line, their alignment is determined by
same-line-style. - If
aloneistrue, it will not participate in the alignment of labels on the same line.
- It can be taken:
label-width: array | auto | dictionary | function | length = auto: The width of the label.auto: Uses the native behavior.length: The width of the label.dictionary, with keys:amount:length,auto, or"max".style:"default","constant","auto", or"native".
- The first case is equivalent to
(amount: len, style: "default"), wherelenis the specified width value; The second case is equivalent to(amount: max-width, style: "native"), wheremax-widthis the maximum width of labels at the current level. - Here,
amountalso represents the hanging indent of the item’s body (i.e., for the default style, the hanging indent length =amount+body-indent; for the paragraph style, the hanging indent length =amount). - When
amountis"max", the value ofamountis the maximum actual width of labels at the current level.
label-format: array | function | none = none: Customize labels in any way. It takesnone: Does not take effectfunction- The form is:
it => ..., Accessit.bodyto get the label content,it.levelfor the current label’s levelit.nfor the current label’s index, andit.n-lastfor the index of the last label in the current level
- The form is:
array- The (
level-1)-th element of the array applies to the label at thelevel-th level. - Each element in the array can be:
- A
functionwith the formbody => ..., which applies the label’s content to this function. - A
content, which outputs this content directly. autoornone, which means no processing will be done.- An
array:
- Its elements follow the meanings of 1, 2, and 3 above.
- The (
n-1)-th element of the array applies to then-th item’s label at the current level.
- A
- The (
- This method can not only control the style of labels, but also control the content displayed by the current label. In the current version
0.2.x, we recommend usingenum.numbering(along with thenumblypackage) to control the output content of labels inenum, andlist.markerto control the output content of labels inlist.
-
Other features:
auto-base-level: bool = false: To maintain compatibility with native behavior, the display ofnumberingandmarkerstill uses absolute levels. This means even if you reconfigureenum.numberingandlist.markerin sublists, the display ofnumberingandmarkerin sublists follows the absolute level rules. Default:false.- If
auto-base-levelis set totrue, then it treats the current level as 1. - ⚠️ Breaking change: When configuring enums and lists using
*-enum-list,*-enum, or*-list, the current level is treated as 1.
- If
checklist: array | bool = false: Enables checklist. Alternatively, You can also enable and configure checklist-related features using the methodconfig.checklist.auto-resuming: auto | bool | none = none: Relate to the featureResuming Enum.none: Disables this feature.auto: Enables this feature. In this case, the following methods can be used.- Use the method
resume()to continue using the enum numbers from the previous enum at the same level. - Use
resume[...]to explicitly continue using the enum numbers from the previous level (especially in ambiguous cases) and treat the[...]as a newenum. - Use the method
resume-label(<some-label>)to label the enum you want to resume, and then useresume-list(<some-label>)in the desired enum to continue using the labelled enum numbers. - Or use the method
auto-resume-enum(auto-resuming: true)[...], where all enum numbers within[...]will continue from the previous ones. - The method
isolated-resume-enum[...]allows the[...]to be treated as a new enum with independent numbering, without affecting other enums. bool|array: Ifauto-resumingis set totrue, all enum numbers will continue from the previous ones. It can also be set as an array, e.g.,(false, true)means the first level does not enable the resuming feature, while subsequent levels do.
- Use the method
auto-label-width: array | bool | "all" | "each" | "list" | "enum" | auto | none | = none: To ensure consistent first-line indentation of the body across different enums and lists, you can now setauto-label-widthtoautoand use the methodauto-label-itemto align the sublists within.none: Disables this feature.auto: Enables this feature and uses the methodauto-label-itemto align the sublists within.- “all”, “each”, “list”, “enum” or an array: The values and meanings of
auto-label-widthare the same as those of theformparameter in theauto-label-itemmethod.
-
Separate setting of
enumandlistenum-config: dictionary = (:): Configureenum, currently allowed properties (keys) are:indent,body-indent,label-indent,is-full-width,item-spacing,enum-spacing,enum-margin,hanging-indent,line-indent,label-width,label-align,label-baseline,label-format,body-format,- any named arguments of the function
text
list-config: dictionary = (:): Configurelist. Similar toenum-config
This method allows customizing the labels and bodies of enums and lists by level and item.
See manual.pdf and also the source code manual.typ for more details.
Breaking Change: ⚠️
New Feature: 🆕 for ver0.2.x
If you were using ver0.1.x, please read this section carefully when upgrading to ver0.2.x, as we have made some changes to the configuration methods.
-
Two styles of enum-list: Default (native typst) and Paragraph
-
Customize labels and bodies for enums and lists by level and item
-
🆕 Allow per-item configuration
-
🆕 Enable loop usage of array element values:
LOOP -
🆕 If a property can be set at both the level and item, it allows passing a function
- The function format is now standardized as
it => ..., where you can control it by accessing its properties, typicallyit.levelandit.n- More properties may be added in the future
- ⚠️ Breaking change: Properties related to horizontal spacing now follow this format, and additional properties like
it.label-width(stores the actual maximum width of the label) andit.e(represents the current level’s construction object: enum or list) are provided - ⚠️ Breaking change: Deprecated
level,level-count, andlist-level- Using these methods to configure enum and list properties may sometimes cause “layout did not converge within 5 attempts”
- In ver0.1.x, per-level and per-item settings for
enum.numberingcan now be combined with thenumblypackage and thelabel-formatmethod
- The function format is now standardized as
-
🆕 When using the
*-enum-listmethod, you can separately configure enums and lists:enum-config,list-config -
Horizontal spacing settings:
indent,body-indent,label-indent,enum-margin(is-full-width) -
Vertical spacing settings:
item-spacing,enum-spacing -
Label customization
text-style(…args)- 🆕
label-align - 🆕
label-baseline - 🆕
label-format - 🆕
label-width
-
🆕 Label alignment between items at different levels:
auto-label-width -
auto-base-level- ⚠️ Breaking change: When configuring enums and lists using
*-enum-list,*-enum, or*-list, the current level is treated as 1- Version 0.1.x used absolute levels
- To maintain compatibility with native behavior, the display of numbering and markers still follows absolute levels. Even if you reconfigure
enum.numberingandlist.markerin sublists, their display adheres to absolute level rules- In this case,
auto-base-levelis set totrue, treating the current level as 1
- In this case,
- ⚠️ Breaking change: When configuring enums and lists using
-
Body formatting:
hanging-indent,line-indent- 🆕
body-format:text-style:style- Border settings:
outer,inner,whole: (stroke,radius,outset,fill,inset)
- Experimental:
item-format
- 🆕
-
-
Enum numbering references:
elabelandconfig.ref- ⚠️ The
ref-enummethod from ver0.1.x will be deprecated in the future. Please useconfig.reffor configuration
- ⚠️ The
-
Resume enum
issue#1- 🆕
auto-resumingnone: Disable resume functionalityauto: Using the following methods:resumeresume-label,resume-listauto-resume-enumisolated-resume-enum(independent sublists)
- Globally use
trueor(true, false)etc. to enable functionality;falsemeans the functionality does not apply to this level
- 🆕
-
List enhancements
- Enhanced
list.marker: Allows passing afunctionparameter in the form oflevel => n => contentorlevel => array - 🆕 Terms-like functionality:
item - 🆕 Checklist (from the
cheqpackage, with minor enhancements and fixes for compatibility withitemize)- Configure using
config.checklist
- Configure using
- Enhanced
-
Add manual
-
Fixes
-
Alignment of labels and bodies
-
🆕 Block-level elements displayed on the same line (
issue#4)-
Now better handles blank content in typst, ensuring correct alignment
-
Due to limitations in typst, content within
contextcannot be retrieved in pure typst, making it impossible to correctly process cases like:#show: el.default-enum-list + #context {block[#text.fill]}- Temporary solution: Use
layout(_ => {...})instead ofcontext {...}, e.g.,#show: el.default-enum-list + #layout(_ => {block[#text.fill]})
- Temporary solution: Use
-
Similarly, output content in
ref(...)cannot be processed -
For block-level elements, our handling is more refined compared to native behavior:
- If a block-level element behaves like a paragraph (
par,pad,block,repeat,layout), it is treated as paragraph behavior, ensuring alignment of labels and bodies within the same paragraph - If it is not a paragraph (
block-equation,block-rawrect,table,grid,stack,heading,figure, etc.), it follows native behavior - [?]
alignhere is paragraph behavior but cannot be correctly implemented (currently follows native behavior)
- If a block-level element behaves like a paragraph (
-
-
Resolved some cases where “layout did not converge within 5 attempts” occurred
- However, this may lead to “maximum show rule depth exceeded” when nesting levels increase
- Mainly occurs with complex configurations of
label-formatandbody-format
-
Other fixes:
-
Support for
enum.start -
⚠️ Breaking change: For compatibility with the native
list.markerbehavior, unlike the methods provided byitemize, the level here starts from 0 (seeissue#3). -
Fixed: Incorrect label display when mixing enums and lists with
*-enumand*-listconfigurations- Now, we rewrite both behaviors of
enumandlist, but*-enumdoes not configure list formatting, and similarly for*-list
- Now, we rewrite both behaviors of
-
Compatibility with typst 0.14 behavior (
[#6609]and[#6242])
-
-
This project is licensed under the MIT License.