How come this does not generate a grid as expected?

Hello!

I have the following code:

// Define the vimg function to create image rectangles with text
#let vimg(body) = {
  rect(width: 50mm, height: 30mm)[
    #text(body)
  ]
}

// Example logos array for testing
#let Example_logos = ("Example 1", "Example 2", "Example 3", "Example 4")

// Example 1: Manual Approach (Works as Expected)
#figure(
  grid(
    columns: 2,       // Enforce a two-column layout
    gutter: 20mm,     // Space between columns

    // Manually adding each logo, assuming we have four logos for example
    vimg("Example 1"),
    vimg("Example 2"),
    vimg("Example 3"),
    vimg("Example 4")
  )
)

// Example 2: For Loop Approach (Problem Case)
#figure(
  grid(
    columns: 2,       // Enforce a two-column layout
    gutter: 20mm,     // Space between columns

    // Using a `for` loop to add each logo dynamically
    if Example_logos != none {
      for logo in Example_logos {
        vimg(logo)
      }
    }
  )
)

It generates the following:

What I want is the first, where I do it manually and the 4 inputs are lay out in a grid. When using the for loop it becomes just one vertical line?

I want to use grid and get this to work with for loop. No packages.

Kind regards

By using a for loop for inserting the images, you end up creating just a single grid cell that contains a sequence of all images. What you need to use, is the spreading of arguments via the .. operator, which is then easiest done not with a for loop, but by mapping the Example_logos array to an array of image elements. Assuming that Example_logos is not none, you can then write this as

grid(
  columns: 2,
  gutter: 20mm,
  ..Example_logos.map(vimg)
)

If you still prefer a for loop, you need to make sure that an array is built from it, and not a single piece of content containing all the images. As the results of each loop iteration are in the end joined together, you need to make sure that each iteration yields an array with the image as its single entry:

grid(
  columns: 2,
  gutter: 20mm,
  ..for logo in Example_logos {
    (vimg(logo),)
  }
)

If you cannot always assume that Example_logos isn’t none, you can put the if statement after the .., so that whatever is inside that statement is spread into the arguments of the grid:

grid(
  columns: 2,
  gutter: 20mm,
  ..if Example_logos != none {
    Example_logos.map(vimg)
  }
)

On an unrelated note, please try to put questions in the Questions category, so that it’s easier to find for other people. This will also allow you to later mark a solution. Also, you can get proper Typst syntax highlighting by creating your code blocks with a language identifier as in

```typ
#let vimg(body) = { ... }
```
2 Likes

Thank you Eric, a very simple question I had but a great explanation I could follow.

Kind regards

2 Likes