quarto-dev / quarto-dev/quarto-cli

Dashboard tabset: second tab has inverted row/column layout orientation

Open
#14,222 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug dashboards
Dominant language
JavaScript
Stars
6k
Forks
458
Avg merge
1d 9h
Merged PRs (30d)
41

Description

I have:
  • searched the issue tracker for similar issues
  • installed the latest version of Quarto CLI
  • formatted my issue following the Bug Reports guide
Bug description

When a dashboard tabset contains tabs with nested #### Column and ##### Row layout headings, all even-positioned tabs (2nd, 4th, 6th...) render with inverted grid orientation (rows become columns, columns become rows). Odd-positioned tabs render correctly.

Steps to reproduce
---
title: "Second tab has inverted layout orientation"
format: dashboard
---

## Row {.tabset}

### Tab A

#### Column

##### Row

::: {.card title="Card 1"}
Should be side-by-side with Card 2
:::

::: {.card title="Card 2"}
Should be side-by-side with Card 1
:::

### Tab B

#### Column

##### Row

::: {.card title="Card 1"}
Should be side-by-side with Card 2 **BUT IS STACKED**
:::

::: {.card title="Card 2"}
Should be side-by-side with Card 1 **BUT IS STACKED**
:::

### Tab C

#### Column

##### Row

::: {.card title="Card 1"}
Should be side-by-side with Card 2
:::

::: {.card title="Card 2"}
Should be side-by-side with Card 1
:::
Actual behavior
  • Tab A: Cards are side-by-side (correct)
  • Tab B: Cards are stacked vertically (wrong - layout is inverted)
  • Tab C: Cards are side-by-side (correct)

Inspecting the HTML shows Tab B has grid-template-rows where Tab A and C have grid-template-columns, and vice versa for nested elements.

Expected behavior

All three tabs should render identically with cards side-by-side.

Possible root cause analysis

(I updated this as Claude had a few hypotheses before this conclusion we got to after we found a temp workaround of adding new dummy tabs which are hidden)

The bug is in the dashboard Lua filters. Two pieces of global mutable state persist across tab processing:

  1. lastLevel in main.lua (~line 7683) - tracks the last heading level seen
  2. currentOrientation in layout.lua (line 123) - tracks current layout orientation

The orientation logic in main.lua (~lines 8087-8097) rotates orientation when a new heading level is encountered:

local toOrientation = dashboard.layout.currentOrientation()
if level ~= lastLevel then
  lastLevel = level
  toOrientation = dashboard.layout.rotatedOrientation()
end

And orientContents mutates currentOrientation as a side effect.

When processing tabs with nested #### Column (level 4) and ##### Row (level 5):

  1. Tab A: #### Column is level 4 (new), rotates. ##### Row is level 5 (new), rotates again. After processing, lastLevel=5.

  2. Tab B: #### Column is level 4, but lastLevel is still 5 from Tab A. Since 4 ≠ 5, it rotates when it shouldn't. Then ##### Row is level 5, same as the new lastLevel, so it doesn't rotate when it should. Result: inverted layout.

  3. Tab C: Same pattern as Tab B, but the double-wrong rotations happen to cancel out and produce the correct layout.

This affects all even-positioned tabs (2, 4, 6...), not just the second one.

The fix should reset lastLevel before processing each tab's contents, so each tab starts fresh rather than inheriting state from the previous sibling.

Your environment

IDE: Positron 2025.02.0-149
OS: Ubuntu 24.04.4 LTS

Quarto check output
Quarto 1.9.35
[✓] Checking versions of quarto binary dependencies...
      Pandoc version 3.8.3: OK
      Dart Sass version 1.87.0: OK
      Deno version 2.4.5: OK
      Typst version 0.14.2: OK
[✓] Checking Quarto installation......OK
      Version: 1.9.35
      Path: /opt/quarto/bin
[✓] Checking R installation...........OK
      Version: 4.5.2
      knitr: 1.51
      rmarkdown: 2.30

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in main.lua around the tab and heading-processing logic near lines 7683 and 8087-8097, then inspect currentOrientation and orientContents in layout.lua around line 123. Reproduce the supplied Quarto dashboard and verify that resetting tab-level state makes every tab render its cards side-by-side.

Written by the indexing model from the issue text.

Assessment

Tech stack
lua
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.