Skip to content

fix(error-tracking): stop exception card header label overlapping the tabs - #88176

Merged
trunk-io[bot] merged 3 commits into
masterfrom
cat/exception-card-header-overflow
Aug 25, 2026
Merged

trunk-io[bot] merged 3 commits into
masterfrom
cat/exception-card-header-overflow

Conversation

@cat-ph

@cat-ph cat-ph commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Anyone opening an exception in a narrow pane — a split view, or a phone — saw the exception card header render ExStackpTrace: the "Exception" label painted on top of the tab bar instead of getting out of its way.

Three things combine in that one 40px row:

  • the label cell carries min-w-0, which lets its grid track collapse below the label's width, but nothing clipped the overflow — so the text spilled over its neighbour rather than disappearing
  • the 1fr auto 1fr template reserves two equal gutters to centre the tab bar, so the header needs 2 x label + tabs of width before anything fits, even though only one gutter has content — which reaches the collapsing regime early
  • the tab bar is w-fit + whitespace-nowrap in an auto track, so under ~390px it overflows the header with nothing catching it

Changes

The header now degrades on a priority order — the action never goes, the tab bar next, the label first — keyed to the card's own width through a container query rather than the viewport, because the card lives in a resizable split pane.

card under 576px card at 576px and up
label logomark only; the text drops to sr-only, so it stays in the accessibility tree logomark + "Exception", truncating
tab bar takes the remaining space, left-aligned, scrolls if still short intrinsic width, centred in the header
action auto track: never shrinks, never clipped same

overflow-hidden on the label cell is the actual overlap fix; the rest is what keeps the clip from being the first thing a person notices. The tab bar also picks up justify-start, overriding the list's own justify-center — a centred flex row that overflows spills off both edges, which would leave the first tab out of reach of the scroller.

Screenshots

Every shot is the new ExceptionCardHeaderWidths story, one card per width, rendered in Storybook.

Before — the overlap reproduces at 300px (ExStackpTrace) and 420px (ExceptStack Trace), and is absent from 560px up, which is why it only shows in a narrow pane:

before

After — the label gives way to the logomark below 576px and the tab bar takes the slack, scrolling at 300px:

after

After, with the right-hand cell occupied (ExceptionCardHeaderWidthsWithAction) — the tightest the tab bar ever gets, and View logs stays whole at every width:

after, action occupied

How did you test this code?

ExceptionCardHeaderWidths and ExceptionCardHeaderWidthsWithAction pin each branch of the container query at 300 / 420 / 560 / 576 / 900px, the second with the right-hand action occupied so the tab bar has the least room it ever gets. Both are untagged, so visual review snapshots them. The regression they catch is the overlap itself, which no jsdom test can see — it is purely a layout outcome.

Verified by rendering those same stories against the pre-fix component: the overlap reproduces at 300px and 420px, and is gone after.

Automated checks run locally, all clean: oxfmt --check, oxlint, tsgo --noEmit. No manual testing in the running app.

Expected visual review diff

exception-card-with-footer changes on purpose. It rendered at an accidental width — w-full resolves against a shrink-to-fit storybook wrapper, so the card sized to its own content — and it now has a definite w-[1000px] like the other card stories.

Worth knowing for anyone reusing the container-query pattern: container-type: inline-size makes an element's width independent of its contents, so it contributes nothing to a shrink-to-fit ancestor. Putting it on the whole card collapsed that story to 32px. The container wraps the header alone for that reason.

Automatic notifications

  • Publish to changelog?

Docs update

None — no user-facing behaviour beyond the layout itself.

Agent context

Autonomy: Human-driven (agent-assisted)

Authored with Claude Code (Opus 5). Skills invoked: /pr-closeout and /autoreview, the latter running Codex against the branch diff — it returned clean with no actionable findings.

Two decisions changed across the session, both caught by screenshotting the stories rather than by reading the CSS. The breakpoint started at @lg (512px), where the label reappears but immediately truncates to Exce..., since symmetric gutters leave only ~78px a side at that width; it moved to @xl (576px), where the full label fits. The centred-overflow clipping in the tab bar surfaced the same way.

… tabs

The header's label cell carried `min-w-0` with nothing clipping it, so once its
grid track collapsed the "Exception" label painted straight over the tab bar
instead of disappearing. The symmetric `1fr auto 1fr` template brought that on
early: it reserves two equal gutters to centre the tab bar even though only one
gutter has content.

Clip the label cell, and degrade the header on the card's own width — a
container query, since the card lives in a resizable split pane where viewport
breakpoints say nothing useful. Below @XL the label drops to sr-only and the
tab bar takes the slack; at @XL and up the symmetric gutters and centred tab
bar come back. The action cell sits in an `auto` track so it never shrinks, and
the tab bar scrolls (justify-start, so a centred overflow can't put the first
tab out of reach) as a last valve.

Adds ExceptionCardHeaderWidths and ExceptionCardHeaderWidthsWithAction stories
pinning each branch, the second with the right-hand action occupied.
@cat-ph cat-ph self-assigned this Aug 24, 2026
@trunk-io

trunk-io Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

😎 Merged successfully - details.

@github-actions

github-actions Bot commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

✅ Trunk lane — non-backend lane

This PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.

⚠️ Bundle size — 🔺 +173.7 KiB (+0.2%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 68.94 MiB · 🔺 +173.7 KiB (+0.2%)

File Size Δ vs base
render-query/src/render-query/render-query.js 21.64 MiB 🟢 -291.5 KiB (-1.3%)
posthog-app/src/sharedChunkAnchors.js 247.2 KiB 🔺 +245.7 KiB (+16619.6%)
exporter/src/exporterSharedChunkAnchors.js 247.0 KiB 🔺 +245.7 KiB (+18777.3%)
posthog-app/src/lib/components/Shortcuts/utils/DebugCHQueriesImpl.js 14.9 KiB 🟢 -18.5 KiB (-55.3%)
posthog-app/_parent/products/stamphog/frontend/scenes/StamphogDigestsScene/StamphogDigestsScene.js 7.2 KiB 🟢 -1.2 KiB (-14.3%)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

✅ Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.36 MiB · 22 files 🔺 +718 B (+0.1%) ███░░░░░░░ 30.2% of 4.51 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.76 MiB · 3,235 files 🔺 +102 B (+0.0%) █████████░ 90.2% of 9.71 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.5 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
3.9 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.4 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
789 B src/scenes/ChunkLoadErrorBoundary.tsx
762 B src/index.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
304.9 KiB ../node_modules/.pnpm/posthog-js@1.418.16/node_modules/posthog-js/dist/rrweb.js
267.7 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
258.5 KiB ../node_modules/.pnpm/posthog-js@1.418.16/node_modules/posthog-js/dist/module.js
246.0 KiB src/taxonomy/core-filter-definitions-by-group.json
154.2 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
104.6 KiB src/lib/api.ts
95.1 KiB ../packages/quill/packages/quill/dist/index.js
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

✅ Toolbar bundle — eager 2.25 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.25 MiB · 17 files 🔺 +830 B (+0.0%) ████░░░░░░ 39.3% of 5.72 MiB
Deferred (lazy) 2.09 MiB · 33 files 🟢 -950 B (-0.0%) n/a — loads on demand
Loader dist/toolbar.js 1.1 KiB no change █░░░░░░░░░ 5.8% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
745.2 KiB dist/toolbar/toolbar-app-BJUP7HKG.css
582.9 KiB dist/toolbar/chunk-chunk-FNIJRHDL.js
484.6 KiB dist/toolbar/chunk-chunk-GTGJDCUD.js
133.8 KiB dist/toolbar/chunk-chunk-TUAYUMDK.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.2 KiB dist/toolbar/toolbar-app-KEMKGXST.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-LAHTWA76.js
20.9 KiB dist/toolbar/chunk-chunk-ZY7FI6JJ.js
12.2 KiB dist/toolbar/chunk-chunk-PIK3PADE.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

✅ Dist folder size — 🟢 -1.86 MiB (-0.1%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 1462.74 MiB · 🟢 -1.86 MiB (-0.1%)

@github-actions

github-actions Bot commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

🦔 Hogbox preview · ✅ ready

▶ Open the preview

🔑 Login test@posthog.com / 12345678 (demo data)
🧩 Running this PR's backend and frontend, on the PostHog :master base
🔗 Link stable across rebuilds — a re-push swaps the box underneath, the URL stays
🔒 Access tailnet only (PostHog VPN)
🛠️ Admin inspect & debug state in hogland
💤 Idle sleeps after ~30 min idle (snapshot to S3, zero node cost) and wakes on your next visit in ~30s, behind a brief "waking up" screen

commit 01cfd9c · box box-152abafa9cd6 · ready in 703s (push → usable) · build log · rebuilds on every push, torn down on close

@greptile-apps

greptile-apps Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "fix(error-tracking): stop exception card..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b3f6159281

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@trunk-io

trunk-io Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

View Full Report ↗︎ ⋅ Docs

Three fixes from review on the header layout change.

Inline-size containment makes an element's width independent of its contents,
so it contributes nothing to a shrink-to-fit ancestor. With the container on
the Tabs root that covered the whole card, which collapsed it to zero wherever
its width came from its content — visual review caught this on
`exception-card-with-footer`, rendering at 32px instead of 570px. The container
now wraps the header alone, so the card is still sized by its body. That story
also gains a definite width, like its siblings: `w-full` resolves against a
shrink-to-fit storybook wrapper, so the card was sizing to its own content
rather than to the story.

Base UI scrolls the active tab into view on mount and on keyboard navigation,
but not when the value changes from elsewhere. The timeline switches to the
recording tab on a timestamp click, which in a narrow pane left the active tab
outside the scroller with no scrollbar to reveal it. Nudging scrollLeft rather
than calling scrollIntoView keeps ancestors where they are.

Comments no longer narrate what the layout used to do, per the AGENTS.md rule
against change history in source; that belongs in the commit and the PR.
8 updated
Run: 020d378b-5f94-4ae4-969a-912843ab9563

Co-authored-by: cat-ph <268578347+cat-ph@users.noreply.github.com>
@trunk-io
trunk-io Bot merged commit d40ffaa into master Aug 25, 2026
204 checks passed
@trunk-io
trunk-io Bot deleted the cat/exception-card-header-overflow branch August 25, 2026 17:08
@deployment-status-posthog

deployment-status-posthog Bot commented Aug 25, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-08-25 17:42 UTC Run
prod-us ✅ Deployed 2026-08-25 18:34 UTC Run
prod-eu ✅ Deployed 2026-08-25 18:37 UTC Run

This branch was successfully deployed

1 active deployment
preview-pr-88176 — 01cfd9cf Deployed Aug 25, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants