Skip to content

Plotly figures in initially hidden tabs of a panel-tabset don't fill the tab width #14939

Description

@devmcp

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

Update: this is a duplicate of #4705. A fix for the width problem is in #14940.

Plotly figures in any tab other than the one active on page load don't fill the width of the tab. They render at Plotly's default size (700px wide, 450px tall) and only resize when the browser window is resized (e.g. by zooming in or out).

As far as I can tell, the cause is:

  • Plotly.js resizes responsive figures (plotly.py sets responsive: true by default) from a window resize listener.
  • Figures in hidden tabs are drawn while their container has no width, so they fall back to the 700px default.
  • When a tab is shown, src/resources/formats/html/quarto.js dispatches a slideenter event (for htmlwidgets), but no window resize event, so Plotly never re-measures the figure.

This was previously raised in discussion #2082. I misfiled it in quarto-dev/quarto#876, which I'll close in favour of #4705.

I used an AI assistant (Claude Code, with a local clone of this repository) to help investigate. I've reproduced the problem and checked the measurements below on my own machine.

Steps to reproduce

  1. Save the document below as plotly-tabset.qmd and run quarto preview plotly-tabset.qmd.
  2. In the browser window that opens (wider than about 900px), click "Tab 2".

Opening the rendered HTML file directly from disk also shows the problem. However, Chrome and Safari don't run Quarto's JavaScript for local files (quarto.js is loaded as a module), so a fix can't be checked that way unless the document uses embed-resources: true.

---
title: "Plotly in a tabset"
format:
  html:
    page-layout: full
engine: jupyter
---

::: {.panel-tabset}

## Tab 1

```{python}
import plotly.graph_objects as go

go.Figure(go.Scatter(x=[1, 2, 3], y=[1, 3, 2]))
```

## Tab 2

```{python}
go.Figure(go.Scatter(x=[1, 2, 3], y=[1, 3, 2]))
```

:::

Actual behavior

The figure in Tab 2 is 700px wide and 450px tall (Plotly's defaults), while the tab is wider. It only fills the tab after the browser window is resized, e.g. by zooming in or out.

The figure in Tab 1 fills the tab correctly, at the 525px height plotly.py sets.

Expected behavior

The figure in Tab 2 fills the width of the tab as soon as the tab is shown, as the figure in Tab 1 does.

Your environment

  • IDE: none (quarto render and quarto preview in a terminal)
  • OS: macOS 27.0 (26A428)
  • Browsers: Chromium, Firefox and WebKit (Safari)
  • Quarto: 1.11.5 (latest pre-release). Also reproduced on 1.10.18 (latest release).
  • Python 3.13.15, plotly 7.1.0 (bundles plotly.js 4.0.0), Jupyter 5.9.1. Also reproduced with plotly 6.6.0.
  • Quarto 1.11.5 was run from the extracted release tarball, with Python from a clean virtual environment, which is why quarto check shows temporary paths.

Quarto check output

Quarto 1.11.5
[✓] Checking environment information...
      Quarto cache location: /Users/pipe/Library/Caches/quarto
[✓] Checking versions of quarto binary dependencies...
      Pandoc version 3.10.0: OK
      Dart Sass version 1.101.0: OK
      Deno version 2.7.14: OK
      Typst version 0.15.1: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
      Version: 1.11.5
      Path: /private/tmp/claude-501/-Users-pipe-dev-quarto-cli/4ff4e887-06d4-4285-8444-0347ba6fa5a4/scratchpad/q1115/bin
[✓] Checking tools....................OK
      TinyTeX: (not installed)
      Chrome Headless Shell: (not installed)
      VeraPDF: (not installed)
[✓] Checking LaTeX....................OK
      Tex:  (not detected)
[✓] Checking Chrome Headless....................OK
      Using: Chrome found on system
      Path: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
      Source: MacOS known location
[✓] Checking basic markdown render....OK
[✓] Checking R installation...........OK
      Version: 4.5.1
      Path: /Library/Frameworks/R.framework/Resources
      LibPaths:
        - /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/library
      knitr: (None)
      rmarkdown: (None)
      The knitr package is not available in this R installation.
      Install with install.packages("knitr")
      The rmarkdown package is not available in this R installation.
      Install with install.packages("rmarkdown")
[✓] Checking Python 3 installation....OK
      Version: 3.13.15
      Path: /private/tmp/claude-501/-Users-pipe-dev-quarto-cli/4ff4e887-06d4-4285-8444-0347ba6fa5a4/scratchpad/venv-plotly/bin/python
      Jupyter: 5.9.1
      Kernels: pathfinder, python3
[IPKernelApp] WARNING | Kernel is running over TCP without encryption. All communication (including code and outputs) is sent in plain text and is susceptible to eavesdropping. Use IPC transport or launch with kernel manager-provisioned CurveZMQ keys to enable transport encryption.
[✓] Checking Jupyter engine render....OK
[✓] Checking Julia installation...

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions