Skip to content

Code block copy/download buttons unclickable in nested scroll containers (sticky + pointer-events-none) #494

Description

@hebo-agent

Description

When streamdown is embedded in a layout with two or more nested scroll containers (e.g., an outer overflow-auto sidebar + an inner overflow-auto chat scroll), the code block copy/download buttons are visible but unclickable.

Root cause

Streamdown renders code block buttons using a sticky + pointer-events-none/auto pattern:

```html

language label
Copy Download
code body
\`\`\`

In a nested scroll-container layout, hit-testing for the `pointer-events-auto` inner div doesn't work correctly — clicks register on the code-block wrapper instead of reaching the buttons.

Using browser DevTools inspect mode on the button area selects the entire code block wrapper (`div[data-streamdown="code-block"]`), not the button, confirming something intercepts the click before it reaches the button element.

Reproduction steps

  1. Embed streamdown in a layout with 2+ nested scroll containers:
    • Parent: `overflow: auto` (e.g., sidebar)
    • Child: `overflow: auto` (e.g., chat scroll area, such as `use-stick-to-bottom`)
  2. Render a code block with streamdown
  3. Try to click the copy or download buttons — they are visible but do not respond to clicks
  4. In DevTools, use "Select element" and click where the button is — it selects the wrapper div, not the button

Workaround

Switching the button wrapper from `position: sticky` to `position: absolute` makes buttons reliably clickable:

```css
[data-streamdown="code-block"] {
position: relative;
}
[data-streamdown="code-block"] > div:has(> [data-streamdown="code-block-actions"]) {
position: absolute !important;
top: 0.5rem;
right: 0.5rem;
z-index: 1;
margin-top: 0 !important;
pointer-events: auto;
}
```

Trade-off: buttons no longer "stick" when scrolling past long code blocks — they stay at the top of the code block.

Suggested fix

Consider one of:

  • Use `position: absolute` as the default positioning strategy for code block action buttons
  • Provide a CSS custom property or prop to let consumers override the positioning strategy (e.g., `--streamdown-code-actions-position: sticky | absolute`)
  • Investigate and fix the hit-testing issue with `sticky` + `pointer-events-none` in nested scroll contexts

Environment

  • streamdown: 2.5.0
  • Browsers tested: Chrome, Firefox (both affected)
  • Layout: nested scroll containers (sidebar + chat scroll via `use-stick-to-bottom`)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions