Why do `first-line-indent` only be valid when I put a blank line at last line inside `quote`?

I want to set the first-line-indent for paragraph text in quote element. So I wrote this code:

#show quote: set text(font: "Times New Roman")
#show quote: set quote(block: true, quotes: false)
#show quote: set par(first-line-indent: (amount: 2em, all: true))

= Test

#quote(attribution: "From some books", block: true, quotes: false)[
  #lorem(50)
]

Unfortunately, it does not work.

But when I append a blank line after the #lorem(50):

#show quote: set text(font: "Times New Roman")
#show quote: set quote(block: true, quotes: false)
#show quote: set par(first-line-indent: (amount: 2em, all: true))

= Test

#quote(attribution: "From some books", block: true, quotes: false)[
  #lorem(50) // ↓ new line at bottom

]

Then it suddenly works:

image

It’s a confusing behavior for me. I wanna to know why.

I have looked up the documentations for description of paragraph. But I’m a typst newer, pardon me, I can not understand the behavior of why do it perceive a block element after adding blank line.

Thank you. :frowning:

1 Like

Additionally, how do I do if I don’t like appending blank line…It seems to be ugly…

Well there is a tiny bit of magic at work. From your link:

Text in a container (like a block) is only wrapped in a paragraph if the container holds any block-level content. If all of the contents are inline-level, no paragraph is created.

So without the line break it makes sense that there is no paragraph and Typst sees the text as text.

From the second paragraph from the par documentation:

To separate paragraphs, use a blank line (or an explicit parbreak).

The line break is a parbreak and Typst then sees the text as a paragraph.

You can use an explicit par to make sure the text is always recognised as a paragraph.

#quote(attribution: "From some books", par[
  #lorem(50)
])
3 Likes

Additionally, Typst now tells you that “parbreak may not occur inside of a paragraph and was ignored” if you try to add the new line inside the par element.

Separately, the show-set rule for quote is weird. Just use #set quote(block: true) instead of #show quote: set quote(block: true, quotes: false). Also there is no point in specifying block: true, quotes: false for every quote if you already added a set rule for it. quotes is false by default when block is true.

1 Like

I’ll add that, instead of wrapping in par as you suggest, an explicit parbreak (either by explicitly writing #parbreak() after the text, or simply by adding an empty line at the bottom) is a more flexible solution as it allows you to add things that are not text alongside the paragraph, for example an image. Writing #par[text #image(...) text] will generate a warning and not display the image as it cannot go in a paragraph, but #[text #image(...) text #parbreak()] works.

3 Likes

Yeah, but realistically, you wouldn’t want a block-level element in your quote. Unless the quote is…not a regular quote (not how it is meant to be used).

Actually, it matters when the quote is slightly bigger, that includes multiple paragraphs, which is not so uncommon. In that case, parbreak() is the way:

#show quote: set par(first-line-indent: (amount: 2em, all: true))
#set quote(block: true)

= Heading
#quote(attribution: "From some books", [
  #lorem(50)

  #lorem(50)
] + parbreak()) // Can be dropped.

= Heading
#quote(attribution: "From some books", [
  #lorem(50)
] + parbreak())

It can be included in the quote show rule, but you would have to reimplement it.

1 Like

There is also this option (which is what I would realistically use):

#let par-quote(body, ..args) = quote(block: true, body + parbreak(), ..args)

#par-quote(attribution: [Author])[
  Hello world!
  Catch you later!
]
2 Likes