---
description: Typst's tutorial.
---

# Advanced Styling
In the previous two chapters of this tutorial, you have learned how to write a
document in Typst and how to change its formatting. The report you wrote
throughout the last two chapters got a straight A and your supervisor wants to
base a conference paper on it! The report will of course have to comply with the
conference's style guide. Let's see how we can achieve that.

Before we start, let's create a team, invite your supervisor and add them to the
team. You can do this by going back to the app dashboard with the four-circles
icon in the top left corner of the editor. Then, choose the plus icon in the
left toolbar and create a team. Finally, click on the new team and go to its
settings by clicking 'manage team' next to the team name. Now you can invite
your supervisor by email.

![The team settings](3-advanced-team-settings.png)

Next, move your project into the team: Open it, going to its settings by
choosing the gear icon in the left toolbar and selecting your new team from the
owners dropdown. Don't forget to save your changes!

Now, your supervisor can also edit the project and you can both see the changes
in real time. You can join our [Discord server](https://discord.gg/2uDybryKPe)
to find others with preview access and try teams with them!

## The conference guidelines
The layout guidelines are available on the conference website. Let's take a look
at them:

- The font should be an 11pt serif font
- The title should be in 17pt and bold
- The paper contains a single-column abstract and two-column main text
- The abstract should be centered
- The main text should be justified
- First level section headings should be 13pt, centered, and rendered in small
  capitals
- Second level headings are run-ins, italicized and have the same size as the
  body text
- Finally, the pages should be US letter sized, numbered in the center of the
  footer and the top left corner of each page should contain the title of the
  paper

We already know how to do many of these things, but for some of them, we'll need
to learn some new tricks.

## Writing the right set rules
Let's start by writing some set rules for the document.

```example
#set text(font: "Linux Libertine", 11pt)
#set par(justify: true)

#set page(
>>>  margin: auto,
  paper: "us-letter",
  header: align(right + horizon)[
    A fluid dynamic model for
    glacier flow
  ],
  footer: nr => align(
    center + horizon,
    [#nr],
  ),
)

#lorem(600)
```

You are already familiar with most of what is going on here. We set the text
size to `{11pt}` and the font to Linux Libertine. We also enable paragraph
justification and set the page size to US letter.

The `header` and `footer` arguments are new: With these, we can provide content
to fill the top and bottom margins of every page. In the header, we specify our
paper's title as requested by the conference style guide. We use the `align`
function to align the text to the right and the `horizon` keyword to make sure
that it is vertically centered in the margin.

Because we need a page number in the footer, we have to put different content
onto each page. To do that, we can pass a
[custom function]($type/function) to the footer argument that defines
how the footer should look for a given page number. Typst provides the page
number to this function. Once more, we use the `align` function to center the
page number horizontally and vertically.

We have to put the page variable into square brackets and prefix it with a
hashtag because the align function expects
[content,]($type/content) but the page number is an
[integer]($type/integer).

## Creating a title and abstract
Now, let's add a title and an abstract. We'll start with the title. We center
align it and increase its font weight by enclosing it in `[*stars*]`.

```example
>>> #set page(width: 300pt, margin: 30pt)
>>> #set text(font: "Linux Libertine", 11pt)
#align(center, text(17pt)[
  *A fluid dynamic model
  for glacier flow*
])
```

This looks right. We used the `text` function to override the previous text
set rule locally, increasing the size to 17pt for the function's argument. Let's
also add the author list: Since we are writing this paper together with our
supervisor, we'll add our own and their name.

```example
>>> #set page(width: 300pt, margin: 30pt)
>>> #set text(font: "Linux Libertine", 11pt)
>>>
>>> #align(center, text(17pt)[
>>>   *A fluid dynamic model
>>>   for glacier flow*
>>> ])
#grid(
  columns: (1fr, 1fr),
  align(center)[
    Therese Tungsten \
    Artos Institute \
    #link("mailto:tung@artos.edu")
  ],
  align(center)[
    Dr. John Doe \
    Artos Institute \
    #link("mailto:doe@artos.edu")
  ]
)
```

The two author blocks are laid out next to each other. We use the
[`grid`]($func/grid) function to create this layout. With a grid, we can control
exactly how large each column is and which content goes into which cell. The
`columns` argument takes an array of [relative lengths]($type/relative-length)
or [fractions]($type/fraction). In this case, we passed it two equal fractional
sizes, telling it to split the available space into two equal columns. We then
passed two content arguments to the grid function. The first with our own
details, and the second with our supervisors'. We again use the `align` function
to center the content within the column. The grid takes an arbitrary number of
content arguments specifying the cells. Rows are added automatically, but they
can also be manually sized with the `rows` argument.

Now, let's add the abstract. Remember that the conference wants the abstract to
be set ragged and centered.

```example:0,0,612,317.5
>>> #set text(font: "Linux Libertine", 11pt)
>>> #set par(justify: true)
>>> #set page(
>>>   "us-letter",
>>>   margin: auto,
>>>   header: align(right + horizon)[
>>>     A fluid dynamic model for
>>>     glacier flow
>>>   ],
>>>   footer: page => align(
>>>     center+horizon,
>>>     [#page]
>>>   ),
>>> )
>>>
>>> #align(center, text(17pt)[
>>>   *A fluid dynamic model
>>>   for glacier flow*
>>> ])
>>>
>>> #grid(
>>>   columns: (1fr, 1fr),
>>>   align(center)[
>>>     Therese Tungsten \
>>>     Artos Institute \
>>>     #link("mailto:tung@artos.edu")
>>>   ],
>>>   align(center)[
>>>     Dr. John Doe \
>>>     Artos Institute \
>>>     #link("mailto:doe@artos.edu")
>>>   ]
>>> )
>>>
<<< ...

#align(center)[
  #set par(justify: false)
  *Abstract* \
  #lorem(80)
]
>>> #lorem(600)
```

Well done! One notable thing is that we used a set rule within the content
argument of `align` to turn off justification for the abstract. This does not
affect the remainder of the document even though it was specified after the
first set rule because content blocks _scope_ styling. Anything set within a
content block will only affect the content within that block.

Another tweak could be to save the paper title in a variable, so that we do not
have to type it twice, for header and title. We can do that with the `{let}`
keyword:

```example:single
#let title = [
  A fluid dynamic model
  for glacier flow
]

<<< ...

>>> #set text(font: "Linux Libertine", 11pt)
>>> #set par(justify: true)
#set page(
>>> "us-letter",
>>> margin: auto,
  header: align(
    right + horizon,
    title
  ),
<<<   ...
>>> footer: page => align(
>>>   center+horizon,
>>>   [#page]
>>> ),
)

#align(center, text(17pt)[
  *#title*
])

<<< ...

>>> #grid(
>>>   columns: (1fr, 1fr),
>>>   align(center)[
>>>     Therese Tungsten \
>>>     Artos Institute \
>>>     #link("mailto:tung@artos.edu")
>>>   ],
>>>   align(center)[
>>>     Dr. John Doe \
>>>     Artos Institute \
>>>     #link("mailto:doe@artos.edu")
>>>   ]
>>> )
>>>
>>> #align(center)[
>>>   #set par(justify: false)
>>>   *Abstract* \
>>>   #lorem(80)
>>> ]
>>>
>>> #lorem(600)
```

After we bound the content to the `title` variable, we can use it in functions
and also within markup (prefixed by `#`, like functions). This way, if we decide
on another title, we can easily change it in one place.

## Adding columns and headings
The paper above unfortunately looks like a wall of lead. To fix that, let's add
some headings and switch our paper to a two-column layout. The
[`columns`]($func/columns) function takes a number and content, and layouts the
content into the specified number of columns. Since we want everything after the
abstract to be in two columns, we need to apply the column function to our whole
document.

Instead of wrapping the whole document in a giant function call, we can use an
"everything" show rule. To write such a show rule, put a colon directly behind
the show keyword and then provide a function. This function is given the rest of
the document as a parameter. We have called the parameter `rest` here, but you
are free to choose any name. The function can then do anything with this
content. In our case, it passes it on to the `columns` function.

```example:single
>>> #let title = [
>>>   A fluid dynamic model
>>>   for glacier flow
>>> ]
>>>
>>> #set text(font: "Linux Libertine", 11pt)
>>> #set par(justify: true)
>>> #set page(
>>>   "us-letter",
>>>   margin: auto,
>>>   header: align(
>>>     right + horizon,
>>>     title
>>>   ),
>>>   footer: page => align(
>>>     center+horizon,
>>>     [#page]
>>>   ),
>>> )
>>>
>>> #align(center, text(
>>>   17pt,
>>>   weight: "bold",
>>>   title,
>>> ))
>>>
>>> #grid(
>>>   columns: (1fr, 1fr),
>>>   align(center)[
>>>     Therese Tungsten \
>>>     Artos Institute \
>>>     #link("mailto:tung@artos.edu")
>>>   ],
>>>   align(center)[
>>>     Dr. John Doe \
>>>     Artos Institute \
>>>     #link("mailto:doe@artos.edu")
>>>   ]
>>> )
>>>
>>> #align(center)[
>>>   #set par(justify: false)
>>>   *Abstract* \
>>>   #lorem(80)
>>> ]
>>> #v(4mm)
<<< ...

#show: rest => columns(2, rest)

= Introduction
#lorem(300)

= Related Work
#lorem(200)
```

Now there is only one thing left to do: Style our headings. We need to make them
centered and use small capitals. Because the `heading` function does not offer
a way to set any of that, we need to write our own heading show rule.

```example:50,250,265,270
>>> #let title = [
>>>   A fluid dynamic model
>>>   for glacier flow
>>> ]
>>>
>>> #set text(font: "Linux Libertine", 11pt)
>>> #set par(justify: true)
>>> #set page(
>>>   "us-letter",
>>>   margin: auto,
>>>   header: align(
>>>     right + horizon,
>>>     title
>>>   ),
>>>   footer: page => align(
>>>     center + horizon,
>>>     [#page]
>>>   ),
>>> )
#show heading: it => block[
  #set align(center)
  #set text(12pt, weight: "regular")
  #smallcaps(it.body)
]

<<< ...
>>>
>>> #align(center, text(
>>>   17pt,
>>>   weight: "bold",
>>>   title,
>>> ))
>>>
>>> #grid(
>>>   columns: (1fr, 1fr),
>>>   align(center)[
>>>     Therese Tungsten \
>>>     Artos Institute \
>>>     #link("mailto:tung@artos.edu")
>>>   ],
>>>   align(center)[
>>>     Dr. John Doe \
>>>     Artos Institute \
>>>     #link("mailto:doe@artos.edu")
>>>   ]
>>> )
>>>
>>> #align(center)[
>>>   #set par(justify: false)
>>>   *Abstract* \
>>>   #lorem(80)
>>> ]
>>>
>>> #v(4mm)
>>> #show: rest => columns(2, rest)
>>>
>>> = Introduction
>>> #lorem(35)
>>>
>>> == Motivation
>>> #lorem(45)
```

This looks great! We used a show rule that applies to all headings. We give it a
function that gets passed the heading as a parameter. That parameter can be used
as content but it also has some fields like `title`, `numbers`, and `level` from
which we can compose a custom look. Here, we are center-aligning, setting the
font weight to `{"regular"}` because headings are bold by default, and use the
[`smallcaps`]($func/smallcaps) function to render the heading's title in small capitals.

The only remaining problem is that all headings look the same now. The
"Motivation" and "Problem Statement" subsections ought to be italic run in
headers, but right now, they look indistinguishable from the section headings. We
can fix that by using a `where` selector on our set rule: This is a
[method]($scripting/#methods) we can call on headings (and other
elements) that allows us to filter them by their level. We can use it to
differentiate between section and subsection headings:

```example:50,250,265,245
>>> #let title = [
>>>   A fluid dynamic model
>>>   for glacier flow
>>> ]
>>>
>>> #set text(font: "Linux Libertine", 11pt)
>>> #set par(justify: true)
>>> #set page(
>>>   "us-letter",
>>>   margin: auto,
>>>   header: align(
>>>     right + horizon,
>>>     title
>>>   ),
>>>   footer: page => align(
>>>     center + horizon,
>>>     [#page]
>>>   ),
>>> )
>>>
#show heading.where(
  level: 1
): it => block[
  #set align(center)
  #set text(12pt, weight: "regular")
  #smallcaps(it.body)
]

#show heading.where(
  level: 2
): it => text(
  size: 11pt,
  weight: "regular",
  style: "italic",
  it.body + [.],
)
>>>
>>> #align(center, text(
>>>   17pt,
>>>   weight: "bold",
>>>   title,
>>> ))
>>>
>>> #grid(
>>>   columns: (1fr, 1fr),
>>>   align(center)[
>>>     Therese Tungsten \
>>>     Artos Institute \
>>>     #link("mailto:tung@artos.edu")
>>>   ],
>>>   align(center)[
>>>     Dr. John Doe \
>>>     Artos Institute \
>>>     #link("mailto:doe@artos.edu")
>>>   ]
>>> )
>>>
>>> #align(center)[
>>>   #set par(justify: false)
>>>   *Abstract* \
>>>   #lorem(80)
>>> ]
>>>
>>> #v(4mm)
>>> #show: rest => columns(2, rest)
>>>
>>> = Introduction
>>> #lorem(35)
>>>
>>> == Motivation
>>> #lorem(45)
```

This looks great! We wrote two show rules that each selectively apply to the
first and second level headings. We used a `where` selector to filter the
headings by their level. We then rendered the subsection headings as run-ins. We
also automatically add a period to the end of the subsection headings.

Let's review the conference's style guide:
- The font should be an 11pt serif font ✓
- The title should be in 17pt and bold ✓
- The paper contains a single-column abstract and two-column main text ✓
- The abstract should be centered ✓
- The main text should be justified ✓
- First level section headings should be centered, rendered in small caps and in 13pt ✓
- Second level headings are run-ins, italicized and have the same size as the
  body text ✓
- Finally, the pages should be US letter sized, numbered in the center and the
  top left corner of each page should contain the title of the paper ✓

We are now in compliance with all of these styles and can submit the paper to
the conference! The finished paper looks like this:

<img
  src="3-advanced-paper.png"
  alt="The finished paper"
  style="box-shadow: 0 4px 12px rgb(89 85 101 / 20%); width: 500px; max-width: 100%; display: block; margin: 24px auto;"
>

## Review
You have now learned how to create headers and footers, how to use functions and
scopes to locally override styles, how to create more complex layouts with the [`grid`]($func/grid) function and how to write show rules for individual functions, and the whole document. You also learned how to use the
[`where` selector]($styling/#show-rules) to filter the headings by their level.

The paper was a great success! You've met a lot of like-minded researchers at
the conference and are planning a project which you hope to publish at the same
venue next year. You'll need to write a new paper using the same style guide
though, so maybe now you want to create a time-saving template for you and your
team?

In the next section, we will learn how to create templates that can be reused in
multiple documents. This is a more advanced topic, so feel free to come back
to it later if you don't feel up to it right now.
