Prerequisites
- I have searched for duplicate or closed issues
- I have read the contributing guidelines
Describe the issue
On WebKit (Safari, and WKWebView hosts such as Tauri/Electrobun), drag-selecting text in a FileDiff until the selection reaches the viewport edge and the view auto-scrolls crashes the web-content process (Safari shows "A problem repeatedly occurred"; in a WKWebView the whole page reloads/dies).
Conditions:
- The diff must be tall enough to scroll.
- It happens during a native text-selection drag that triggers auto-scroll (dragging to the top/bottom edge and holding). A selection fully inside the viewport (no scroll) is safe.
- Chromium does not hard-crash (the view just scrolls away under the pointer); this is WebKit-specific.
Root cause (bisected): the crash is tied to [data-code] being display: grid. WebKit crashes on native selection + scroll inside a CSS grid. I injected CSS into the component's shadow root and re-ran the exact gesture on WebKit:
| Shadow CSS override | Result |
|---|---|
[data-code]{ display: block } | no crash |
[data-code]{ display: flex; flex-direction: column } | no crash |
[data-code]{ contain: none } / paint / layout / strict | still crashes |
[data-code]{ overflow: visible } / overflow: auto (self-scroll) | still crashes |
[data-code]{ content-visibility: visible }, isolation: isolate, will-change: transform, transform: translateZ(0) | still crashes |
[data-line] / [data-content] / [data-gutter] → display: block | still crashes |
So it is specifically display: grid on the scrolled element that holds the selectable lines — not virtualization (freezing the virtualizer/render does not help), not contain, not overflow, and not which element scrolls (a grid that scrolls itself also crashes).
Because [data-code] must be grid for the gutter/content columns + subgrid row alignment, there is no layout-preserving CSS workaround for consumers (display:block collapses the layout). This needs a change in Diffs (or a WebKit fix).
Suggested direction: render the selectable, scrolled diff lines without display:grid on the scroll element — e.g., a row-major table/flex layout, or manage selection internally (Monaco-style) — so native selection + auto-scroll no longer runs over a scrolled CSS grid.
Reproduction
No sandbox needed — reproduces on your own demo:
- Open Safari (or any WKWebView).
- Open a long
FileDiff(enough lines to scroll), e.g. on https://diffs.com. - Press inside the diff text and drag the selection to the bottom edge; keep holding so the diff auto-scrolls.
- The web-content process crashes.
Confirm the cause: before step 3, inject into the component's shadow root
const s=new CSSStyleSheet(); s.replaceSync('[data-code]{display:block!important}'); shadowRoot.adoptedStyleSheets=[...shadowRoot.adoptedStyleSheets,s];
— the same gesture no longer crashes (layout breaks, but it proves the trigger).
I verified this with Playwright WebKit against a real app embedding @pierre/diffs; happy to share the spec if useful.
What browser(s) are you seeing the problem on?
Safari (WebKit), WKWebView (Tauri/Electrobun). Not Chrome.
What version of @pierre/diffs are you using?
1.5.1 (React FileDiff)
Activity
4Confirmed the exact crash signature from a macOS crash report (~/Library/Logs/DiagnosticReports/com.apple.WebKit.WebContent.Development-*.ips), produced by a standalone repro (pure additions, enableGutterUtility on, native drag-select with auto-scroll) under Playwright WebKit 2311 / Desktop Safari.
Exception: EXC_BREAKPOINT (SIGTRAP) — "Trace/BPT trap: 5" (a WebKit RELEASE_ASSERT/CRASH(), i.e. a deliberate abort, not a segfault).
Crashing thread (top frames):
0 <deduplicated_symbol> // the assert/trap
1 WebCore::EventHandler::handleMouseDraggedEvent(MouseEventWithHitTestResults const&, CheckDragHysteresis) +676
2 WebCore::EventHandler::handleMouseMoveEvent(PlatformMouseEvent const&, HitTestResult*, bool, ...) +1780
3 WebCore::EventHandler::mouseMoved(PlatformMouseEvent const&) +180
4 WebKit::WebFrame::handleMouseEvent(WebMouseEvent const&) +452
5 WebKit::WebPage::mouseEvent(...) +488
6 IPC::handleMessage<Messages::WebPage::MouseEvent, ...> +112
7 WebKit::WebPage::didReceiveMessage(IPC::Connection&, IPC::Decoder&) +3848
... (IPC dispatch / RunLoop)This matches the signature reported here: the assert fires inside EventHandler::handleMouseDraggedEvent while WebKit extends the native selection, as the gutter utility node is re-parented into the hovered line's number cell on each pointermove.
Version note: reproduces on webkit 2311+ (Playwright 1.61 / recent Safari / Electrobun WKWebView), but not on webkit 2140 (Playwright 1.51).
Fix in #1185 — gate gutter-utility placement while a native text-selection drag is in progress (no DOM node is moved under the drag).
Resolved by #1185 — the cause is the gutter utility being re-parented on every pointermove, so a native selection drag mutated the DOM under the in-progress selection.
Verified against the original real-world reproduction on WebKit with no app-side mitigation: all previously crashing drags pass with the fix (details and the control metrics are in https://github.com/pierrecomputer/pierre/pull/1185#issuecomment-6097345436).
Note the two hypotheses raised earlier in this issue are wrong and should be ignored by anyone reading this later: it is neither row virtualization nor display:grid on the scroll container.
yo, this is a ton of ai slop for me to sift through. please try to personally write stuff...
I am definitely not able to repro this... so i'll need more context on how to reproduce this before we go ahead with any PRs:
https://github.com/user-attachments/assets/f7f9c617-9188-4486-94fa-e7605fd4bb0a
Correction / status update — please don't treat
display:gridas the confirmed root cause yet.I originally reported the trigger as
[data-code] { display: grid }, based on a shadow-CSS bisection in our app (display:block/flex→ no crash). That conclusion is not safe: withdisplay:blockthe diff layout collapses and the code text is no longer rendered/selectable, so "no crash" there may simply mean "nothing to select". I'm retracting that specific claim.What is still solid:
com.apple.WebKit.WebContent):EXC_BREAKPOINT/SIGTRAP— aRELEASE_ASSERT, not a segfault — with the faulting stack:[data-code]alone → no crashlineDiffType: "word", review annotations/threads, deletions (a pure-addition new file crashes), multiple filesFileDiff/File/CodeView/Virtualizerrender funnels, verified bundled and active) does not prevent the crashStandalone reproduction is still missing. I built a minimal Vite + React +
@pierre/diffs@1.5.1page (served over http;page.setContentis not enough — selection auto-scroll never engages there) and progressively matched our app: split layout +lineDiffType:"word"+hunkSeparators+collapsedContextThreshold+disableFileHeader,lineAnnotations+renderAnnotation+renderGutterUtility,WorkerPoolContextProvider, pure-addition 1500-line diff, 1280×720 /devices["Desktop Safari"]. Geometry matches our app exactly (outer scrollerscrollHeight≈13772/clientHeight=600,[data-code]display:grid,overflow: scroll hidden) — but it does not crash, and notably the scroller never auto-scrolls during the drag there.So the missing ingredient is whatever makes the diff actually scroll under the live selection in our app. I'm now bisecting top-down from the app (stripping shell/theme/scroll-restore/props) to isolate it, and will post the standalone repro here as soon as it reproduces.