A Typst package for creating horizontal columned lists, similar to LaTeX’s tasks package. Perfect for exercises, multiple-choice questions, and any content that benefits from a compact columned layout.
Gallery
Click on an image to see the source code.
| Basic Tasks | Math Exercises | Custom Labels | Styled Layout |
| Vertical Flow | Column Spanning | Bold Labels | Resume Numbering |
| Adaptive Row Heights | Wrap Zone |
Features
- Indentation-independent parsing - Output is completely independent of source code indentation
- Horizontal flow layout - Items flow left-to-right across columns (like LaTeX’s tasks)
- Flexible column counts - 2, 3, 4 or any number of columns
- Auto-fit columns - Use the largest column count that does not introduce a new wrap or overflow
- Column spanning - Items can span multiple columns using
(N)syntax - Multiple label formats - Alphabetic (
a),A)), numeric (1),(1)), roman (i),I)), bullets, or custom - Bold labels - Make labels stand out with bold weight
- Resume numbering - Continue numbering across multiple task blocks
- Two flow directions - Horizontal (a b | c d) or vertical (a c | b d)
- Global configuration - Set defaults for all tasks in your document
- Shorthand functions -
tasks2,tasks3,tasks4for quick column setup - Spacing & alignment controls - Fine-grained gutters, label alignment, baselines, and block spacing
- Wrap zone - Reserve a top-right corner for overlay content (QR codes, stamps) and flow task rows around it
Manual
A full manual is available as a PDF, with a Typst source version in docs/manual.typ.
Quick Start
#import "@preview/taskize:0.2.9": tasks
#tasks[
+ First item
+ Second item
+ Third item
+ Fourth item
]
Basic Usage
Simple Two-Column Layout
#import "@preview/taskize:0.2.9": tasks
#tasks[
+ $2 + 3 = ?$
+ $5 - 2 = ?$
+ $4 times 3 = ?$
+ $8 div 2 = ?$
]
Three-Column Layout
#import "@preview/taskize:0.2.9": tasks
#tasks(columns: 3)[
+ Option A
+ Option B
+ Option C
+ Option D
+ Option E
+ Option F
]
Auto-Fit Columns
Use columns: "auto-fit" to choose the largest column count that does not make any item wrap or overflow compared with a one-column layout. Limit the search with max-columns.
#import "@preview/taskize:0.2.9": tasks
#tasks(columns: "auto-fit", max-columns: 4)[
+ Medium length task with detail
+ Short
+ Short
+ Short
]
By default, auto-fit uses auto-fit-mode: "fill": an item too wide for one
column automatically spans the minimum number of columns it needs — no
explicit +(N) required — so wide items share rows with densely packed short
items. Use auto-fit-mode: "uniform" when every item must fit one ordinary
column; in that mode, the column count is the largest value where no item
wraps at one-column width, so a wide item can force the whole block to fewer
columns. If an item already wraps in the one-column layout, auto-fit keeps
one column, because no no-wrap multi-column layout exists.
Shorthand Functions
#import "@preview/taskize:0.2.9": tasks2, tasks3, tasks4
// Two columns
#tasks2[
+ Item 1
+ Item 2
]
// Three columns
#tasks3[
+ Item 1
+ Item 2
+ Item 3
]
// Four columns
#tasks4[
+ A
+ B
+ C
+ D
]
Label Formats
Built-in Formats
#import "@preview/taskize:0.2.9": tasks
// Lowercase letters with parenthesis (default)
#tasks(label: "a)")[+ One + Two + Three]
// Uppercase letters
#tasks(label: "A)")[+ One + Two + Three]
// Numbers with parenthesis
#tasks(label: "1)")[+ One + Two + Three]
// Numbers in parentheses
#tasks(label: "(1)")[+ One + Two + Three]
// Lowercase roman numerals
#tasks(label: "i)")[+ One + Two + Three]
// Uppercase roman numerals
#tasks(label: "I)")[+ One + Two + Three]
// Bullet points
#tasks(label: "*")[+ One + Two + Three]
// Dashes
#tasks(label: "-")[+ One + Two + Three]
// No labels
#tasks(label: none)[+ One + Two + Three]
Custom Label Function
#import "@preview/taskize:0.2.9": tasks
// Custom emoji labels
#tasks(label: n => "Q" + str(n) + ":")[
+ What is 2+2?
+ What is the capital of France?
+ What color is the sky?
]
Flow Direction
Horizontal Flow (Default)
Items fill rows first: a b | c d | e f
#import "@preview/taskize:0.2.9": tasks
#tasks(columns: 2, flow: "horizontal")[
+ a
+ b
+ c
+ d
+ e
+ f
]
// Layout:
// a) b)
// c) d)
// e) f)
Vertical Flow
Items fill columns first: a c e | b d f
#import "@preview/taskize:0.2.9": tasks
#tasks(columns: 2, flow: "vertical")[
+ a
+ b
+ c
+ d
+ e
+ f
]
// Layout:
// a) d)
// b) e)
// c) f)
Resuming Numbering
#import "@preview/taskize:0.2.9": tasks, tasks-reset
#tasks[
+ First
+ Second
+ Third
]
Some text between task blocks...
// Continue numbering from where we left off
#tasks(resume: true)[
+ Fourth
+ Fifth
+ Sixth
]
// Reset counter to start fresh
#tasks-reset()
#tasks[
+ Back to one
+ Two again
]
Starting from a Specific Number
#import "@preview/taskize:0.2.9": tasks
#tasks(start: 5)[
+ This is item 5
+ This is item 6
+ This is item 7
]
Global Configuration
Set defaults for all tasks in your document:
#import "@preview/taskize:0.2.9": tasks, tasks-setup
// Configure global defaults
#tasks-setup(
columns: 3,
label-format: "1)",
column-gutter: 1.5em,
row-gutter: 0.8em,
)
// All subsequent tasks use these defaults
#tasks[
+ Item 1
+ Item 2
+ Item 3
]
// Override specific settings per-call
#tasks(columns: 2, label: "a)")[
+ Override A
+ Override B
]
Advanced Features
Label Baseline Alignment
Control the vertical alignment of labels relative to content:
#import "@preview/taskize:0.2.9": tasks
// Center alignment (default)
#tasks(label-baseline: "center")[
+ Short item
+ Multi-line item\
with more text
]
// Top alignment
#tasks(label-baseline: "top")[
+ Item aligned at top
+ Another item
]
// Bottom alignment
#tasks(label-baseline: "bottom")[
+ Item aligned at bottom
+ Another item
]
Bold Labels
Make labels stand out by using bold weight:
#import "@preview/taskize:0.2.9": tasks
// Bold labels for emphasis
#tasks(label-weight: "bold")[
+ Important task
+ Critical item
+ Key point
]
// Regular labels (default)
#tasks(label-weight: "regular")[
+ Normal item
+ Standard task
]
Column Spanning
Items can span multiple columns using the +() or +(N) syntax (no space after +). This is similar to LaTeX’s \task* command:
#import "@preview/taskize:0.2.9": tasks
#tasks(columns: 3)[
+ Short
+ Short
+ Short
+(2) This item spans 2 columns
+ Short
+() This item spans all columns (full width)
+ Normal
+ Normal
]
// Practical example: Multiple choice with explanation
#tasks(columns: 2, label: "A)")[
+ Paris
+ London
+ Berlin
+ Madrid
+() The capital of France is Paris, known for the Eiffel Tower.
]
Syntax:
+ Content- Normal item (spans 1 column)+(2) Content- Spans 2 columns (no space after +)+(3) Content- Spans 3 columns+() Content- Spans all columns (full width)
Notes:
- Important: No space between
+and()or(N) - If an item with span doesn’t fit in the current row, it wraps to the next row
- Column spans are clamped to the total number of columns
- Great for adding explanations, headings, or long content within lists
Parameters Reference
tasks Function
| Parameter | Type | Default | Description |
|---|---|---|---|
columns |
int/string | 2 | Number of columns, or "auto-fit" to choose the largest no-wrap count |
label |
string/function | "a)" |
Label format (shorthand for label-format). "enum" follows the document’s enum numbering, one level per nesting depth |
label-format |
string/function | "a)" |
Label format |
answer-lines |
int | 0 | Dotted lines drawn under each task, for exam sheets |
answer-line-gap |
length | 1.2em | Spacing between those lines |
start |
int | 1 | Starting number for labels |
resume |
bool | false | Continue numbering from previous block |
column-gutter |
length | 1em | Space between columns |
row-gutter |
length/string | 0.6em | Space between rows. "auto" (or "adaptive") sizes rows to the true ink of their content so tall inline math (display fractions, matrices) no longer bleeds into the gutter |
max-columns |
int/auto | auto | Maximum column count tested by columns: "auto-fit"; auto means up to the number of items |
auto-fit-mode |
string | "fill" |
"fill" measures spans at their rendered width; "uniform" requires every item to fit one ordinary column |
auto-fit-tolerance |
length | 0.5pt | Measurement tolerance for auto-fit wrap detection |
label-width |
auto/length | auto | Width reserved for labels |
label-align |
alignment | right | Label alignment |
label-baseline |
string/length | "center" |
Label vertical alignment: "center", "top", "bottom", or length |
label-weight |
string | "regular" |
Label font weight: "regular" or "bold" |
indent-after-label |
length | 0.4em | Space between label and content |
indent |
length | 0pt | Left indentation of entire block |
above |
length | 0.5em | Space before block |
below |
length | 0.5em | Space after block |
flow |
string | "horizontal" |
Flow direction: "horizontal" or "vertical" |
Label Format Options
| Format | Example | Description |
|---|---|---|
"a)" |
a) b) c) | Lowercase letters with closing paren |
"a." |
a. b. c. | Lowercase letters with period |
"(a)" |
(a) (b) © | Lowercase letters in parentheses |
"A)" |
A) B) C) | Uppercase letters with closing paren |
"A." |
A. B. C. | Uppercase letters with period |
"1)" |
1) 2) 3) | Numbers with closing paren |
"1." |
1. 2. 3. | Numbers with period |
"(1)" |
(1) (2) (3) | Numbers in parentheses |
"i)" |
i) ii) iii) | Lowercase roman numerals |
"I)" |
I) II) III) | Uppercase roman numerals |
"*" |
bullet | Bullet points |
"-" |
dash | En-dashes |
none |
(none) | No labels |
| function | custom | Custom function n => content |
Examples
Math Exercise Sheet
#import "@preview/taskize:0.2.9": tasks
= Algebra Practice
Simplify the following expressions:
#tasks(columns: 2)[
+ $x^2 + 2x + 1$
+ $(a + b)^2$
+ $3x - 5 + 2x + 8$
+ $frac(x^2 - 4, x - 2)$
]
Solve for $x$:
#tasks(columns: 2, label: "1)")[
+ $2x + 5 = 13$
+ $x^2 = 16$
+ $3(x - 2) = 15$
+ $frac(x, 4) = 7$
]
Multiple Choice Questions
#import "@preview/taskize:0.2.9": tasks
*Question 1:* What is the capital of France?
#tasks(columns: 2, label: "A)")[
+ London
+ Paris
+ Berlin
+ Madrid
]
*Question 2:* Which planet is closest to the Sun?
#tasks(columns: 2, label: "A)")[
+ Venus
+ Mercury
+ Mars
+ Earth
]
Vocabulary List
#import "@preview/taskize:0.2.9": tasks
= French Vocabulary
#tasks(columns: 3, label: none)[
+ *bonjour* - hello
+ *merci* - thank you
+ *oui* - yes
+ *non* - no
+ *s'il vous plait* - please
+ *au revoir* - goodbye
]
When to Use taskize
taskize is specifically designed for horizontal columned layouts where items flow left-to-right across multiple columns, perfect for exercises, multiple-choice questions, and compact lists. Choose taskize when you need:
- Horizontal flow layout - Items arranged in rows across columns (a b | c d | e f)
- Compact exercise sheets - Mathematical exercises, vocabulary lists, multiple-choice questions
- Flexible column control - Easy 2, 3, 4+ column layouts with shorthand functions
- Resume numbering - Continue numbering across multiple task blocks
- LaTeX tasks compatibility - Familiar syntax for users migrating from LaTeX’s tasks package
Comparison with itemize
itemize is an excellent, feature-rich package for vertical list styling with advanced customization capabilities. Use itemize when you need:
- Vertical lists with advanced styling (colors, custom markers, spacing)
- Nested lists with sophisticated formatting
- Rich marker customization (emojis, custom content, per-item markers)
- Advanced typography control over list appearance
- Complex list hierarchies with fine-grained control
In summary: Use taskize for horizontal multi-column layouts (exercises, quizzes, compact lists), and use itemize for feature-rich vertical lists with advanced styling. They complement each other well for different layout needs.
License
MIT License - see LICENSE file for details.
Changelog
All notable changes to taskize are documented here.
[0.2.9] - 2026-08-19
Added
label: "enum"(#3) — follow the document’s ownenumnumbering instead of repeating the format on every call. A multi-level pattern is honoured by nesting depth: with#set enum(numbering: "1) a)"), a top-level task list numbers1)2)and a nested onea)b). The default is unchanged.answer-lines(#1) — dotted lines under each task for exam sheets, filling the column they land in:#tasks(columns: 2, answer-lines: 2)[...].answer-line-gapsets their spacing, andanswer-dots(count: 3)draws them anywhere on its own. Settable document-wide withtasks-setup.- Items as an array —
#tasks(([One], [Two], [Three]))spells a list out where the one-line+syntax cannot; an entry may carry its span as([wide], 2).
Fixed
- A bare
+inside an item was taken for a new item (#2) —+ What is 2 + 2?was split in two and the rest of the line repeated after it. Typst only starts an item at the head of a line, so a+anywhere else is plain text and is now treated as such. A list written on one line has no item syntax to rely on, so pass the items as an array instead:#tasks(([One], [Two], [Three])), which also takes([wide item], 2)to span columns. - The label of an item that opens inline and continues with a block sat at the top of the cell instead of on the item’s first baseline. An item written as a line of text followed by a nested
taskscall, a figure or a table is not inline as a whole, so it fell back to the top-aligned rendering: with a display fraction on that first line, the number ended up level with the numerator rather than with the text it labels. This is the ordinary shape of a multiple-choice question, and it shows on every item when fractions are set in display style. The item is now indented by the label column and the label pulled back into the margin that frees, so it rides on the first line and shares its baseline. The content itself is passed through untouched, so a nestedtaskskeeps its ownabovespacing exactly. Items that begin with a block keep the previous two-cell rendering, there being no text line to align on. Reported, with this approach, by the MathALÉA team.
[0.2.8] - 2026-07-17
Added
Fixed - Reserve a rectangular zone at the top right of a #tasks call with the wrap-zone parameter (or the shared taskize-wrap-zone state) so task rows flow around overlay content placed there independently — a QR code, a stamp, a logo. Rows overlapping the zone render narrowed beside it; later rows return to full width once the zone’s height is cleared. The shared state is the cross-package contract wrapper packages (e.g. exercise-bank) use to reserve space for content they draw themselves.
- Adaptive row heights -
row-gutter: "auto"(or"adaptive") sizes rows to the true ink of their content, so tall inline math (display fractions, matrices) no longer bleeds into the row-gutter and the configured numeric gutter becomes the real visual gap. Rows with ordinary content keep exactly the same spacing as before. Can be set document-wide withtasks-setup(row-gutter: "adaptive").
[0.2.7] - 2026-07-13
Added
- Auto-fit columns -
columns: "auto-fit"selects the largest column count, bounded bymax-columns(default: up to the number of items), that does not introduce a new item wrap or fixed-size content overflow. Useful for exercises mixing short choices, longer text, math, spans, and small figures. - Auto-spanning in fill mode - with
auto-fit-mode: "fill"(default), a regular+item too wide for one column automatically spans the minimum number of columns it needs — no explicit+(N)required — so wide items share rows with densely packed short items.auto-fit-mode: "uniform"instead requires every item to fit one ordinary column and falls back to fewer columns when the widest item no longer fits.
[0.2.6] - 2026-07-02
Added
- True baseline alignment — with
label-baseline: "center"(default), inline content (text, inline math, symbols) now shares the same paragraph line as the label via hanging-indent layout, so fractions and tall inline elements align their baselines with the label instead of sitting above it
Fixed
compilerminimum lowered from0.14.2to0.14.0— patch releases add no new language features, so users on0.14.0/0.14.1were incorrectly excluded
[0.2.5] - 2026-01-27
Added
- Full manual (
docs/manual.typ+docs/manual.pdf) with structured examples - Expanded gallery with styled configuration and resume numbering examples
Fixed
- Indentation-independent parsing - Tasks now render identically regardless of source code indentation
- All
+items at any indentation level in the sametasks[]block are automatically flattened to the same level - Inconsistent indentation no longer creates nested enums with different numbering
- Moving one character in the source no longer breaks the layout
- All
- Column spanning support - Fixed
+(2)and+()syntax to work correctly with the new parser- Handles both
enum.itemnodes and text nodes starting with “+”
- Handles both
- Multiline tasks now capture unindented continuation lines as part of the previous item
Changed
- Internal parser completely rewritten to recursively extract and flatten all enum items
- Parent items with nested enums (from indentation) have enum nodes stripped from their content
- README gallery layout refreshed and feature list expanded
- Documentation updated for the new manual and examples
[0.2.0] - 2026-01-15
Fixed
- Indentation-independent parsing - Tasks now render identically regardless of source code indentation
- All
+items at any indentation level in the sametasks[]block are automatically flattened to the same level - Inconsistent indentation no longer creates nested enums with different numbering
- Moving one character in the source no longer breaks the layout
- All
- Column spanning support - Fixed
+(2)and+()syntax to work correctly with the new parser- Handles both
enum.itemnodes and text nodes starting with “+”
- Handles both
Changed
- Internal parser completely rewritten to recursively extract and flatten all enum items
- Parent items with nested enums (from indentation) have enum nodes stripped from their content
Added
- Column spanning - Items can span multiple columns using
(N)syntax (e.g.,+ (2) Contentor+ () Full width) label-baselineparameter for controlling vertical alignment of labels ("center","top","bottom", or custom length)label-weightparameter for bold labels ("regular"or"bold")- Advanced Features section in documentation with examples
- Gallery examples for column spanning and bold labels
Changed
- Repository URL updated to GitLab:
https://gitlab.com/nathan-ed/typst-package-taskize - Description enhanced to mention “Horizontal and vertical” flow directions
[0.1.0] - 2026-01-14
Added
- Initial release with horizontal columned list layout
- Flexible column counts (2, 3, 4, or custom)
- Multiple label formats (alphabetic, numeric, roman, bullets, custom)
- Resume numbering across multiple task blocks
- Two flow directions: horizontal (a b | c d) and vertical (a c | b d)
- Global configuration system with
tasks-setup() - Shorthand functions
tasks2,tasks3,tasks4 - Comprehensive parameter customization
- Full documentation with examples and parameter reference