How can I use different page number locations on alternating pages?

How is it possible to place page numbers at the top left corners of odd pages and top right corners of even pages?

┌───────╥───────┐ ┌───────╥───────┐
│ 1     ║     2 │ │ 3     ║     4 │
│       ║       │ │       ║       │
│       ║       │ │       ║       │
│       ║       │ │       ║       │
└───────╨───────┘ └───────╨───────┘

Or maybe the other way around, which is in fact a more correct way to number pages according to book design traditions:

┌───────┐ ┌───────╥───────┐ ┌───────╥───────┐
│     1 │ │ 2     ║     3 │ │ 4     ║     5 │
│       │ │       ║       │ │       ║       │
│       │ │       ║       │ │       ║       │
│       │ │       ║       │ │       ║       │
└───────┘ └───────╨───────┘ └───────╨───────┘

( Page setup guide – Typst Documentation documentation page doesn’t seem to mention this trick. The closest thing I have found there is:

#set page(header: context {
  if counter(page).get().first() > 1 [
    ...
  ]
})

Which can probably be changed like “if page number is divisible by 2, then it is even; otherwise, it is odd”. But then, how to implement this if/else in code? )

#set page(height: auto)

// Starting from left:
// #set page(header: context {
//   let page = counter(page).get().first()
//   let body = if calc.odd(page) [odd ] else [even ] + str(page)
//   let alignment = if calc.odd(page) { left } else { right }
//   align(alignment, body)
// })

// Starting from right (book style):
#set page(header: context {
  let page = counter(page).get().first()
  let body = if calc.odd(page) [odd ] else [even ] + str(page)
  let alignment = if calc.odd(page) { right } else { left }
  align(alignment, body)
})

#range(5).map(_ => pagebreak()).join()

This can be simplified to:

#set page(header: context {
  let page = counter(page).get().first()
  align(if calc.odd(page) { right } else { left })[#page]
})

I have a feeling that this might be achieved in some even easier way, but nothing else comes to mind.

1 Like

if you want a text to alternate with the page number, you could do this:

#set page (header: context {
    // Get the current page number
    let page_num = counter(page).at(here()).first()
    let custom_text = "Your custom text"
    set text(size: 10pt) // Optional: set footer font size
    
    if calc.even(page_num) {
      // Even pages: [page number] on left, "text" on right
      grid(
        columns: (1fr, 1fr),
        align(left, counter(page).display()),
        align(right, [custom_text])
      )
    } else {
      // Odd pages: "text" on left, [page number] on right
      grid(
        columns: (1fr, 1fr),
        align(left, [custom_text]),
        align(right, counter(page).display())
      )
    }
  }
)

Watch the formatting. There cannot be a space character following #set page.

As posted:

#set page (header: context {
...

But it should be:

#set page(header: context {
...