Environment
Self-hosted CE v1.3.1 (docker compose deploy). Reproduced on real iPhone Safari (iOS 26) and with Playwright WebKit (iPhone 13 device profile). Desktop browsers are unaffected (both bugs are WebKit/viewport-specific).
Two independent bugs make the v1.3.1 web app effectively unusable on iOS. Root-cause analysis for both is included below (file/line refs are against the v1.3.1 tag).
Bug 1 — unguarded requestIdleCallback crashes every workspace page on WebKit
Symptom: any workspace page (kanban, list, …) immediately shows the "🚧 Looks like something went wrong!" error boundary.
Console:
TypeError: window.requestIdleCallback is not a function.
(In 'window.requestIdleCallback(()=>{h.current&&(S.current=`${h.current.offsetHeight}px`)})')
React Router caught the following error during render TypeError: window.requestIdleCallback is not a function.
Root cause: Safari/WebKit still does not ship requestIdleCallback (it remains behind an experimental flag), and a layout component rendered by workspace pages calls window.requestIdleCallback(...) unguarded, throwing during render.
Suggested fix: feature-guard the call (window.requestIdleCallback ?? setTimeout fallback) or add a polyfill to the app entry.
Workaround we're running: a setTimeout-based polyfill injected into index.html ahead of the bundle — with it, the pages render fine, which confirms this is the only fatal error on the path.
(While debugging we also consistently see React hydration errors #418/#423 on the prerendered shell in WebKit — non-fatal since React recovers, but noisy and possibly related to Bug 2's state confusion.)
Bug 2 — on <768px viewports the expanded sidebar overlays the entire board and swallows every tap
Symptom: tapping any kanban card does nothing — users report "opening/modifying a card never loads". The peek overlay itself is healthy: programmatically force-clicking a card through the overlay opens it normally.
Evidence: Playwright cannot deliver a tap to any card:
<div id="main-sidebar" ... class="z-20 ... translate-x-0 opacity-100 absolute"> subtree intercepts pointer events
Root cause chain (v1.3.1):
apps/web/core/components/sidebar/resizable-sidebar.tsx (~line 185): when not collapsed the sidebar renders translate-x-0 opacity-100, plus absolute when isMobile — i.e. a full-height z-20 overlay on phones.
- The mobile auto-collapse lives in
apps/web/core/components/sidebar/sidebar-wrapper.tsx (~line 46): if (windowSize[0] < 768 && !sidebarCollapsed) toggleSidebar(). On project/workspace issue pages this component's effect does not end up collapsing the sidebar (and a synthetic resize event doesn't either), so the overlay stays up.
- That effect also calls
toggleSidebar() (toggle) instead of toggleSidebar(true) (set): if it runs more than once (two wrapper instances / re-mounts), the state flips collapsed → expanded again. We observed app_sidebar_collapsed being written "true" then "false" during a single boot on a fresh profile.
store-wrapper.tsx (~line 48) only applies localStorage.app_sidebar_collapsed when it exists, and there is no width-aware default — so a fresh mobile visitor always starts expanded/overlaying.
Suggested fix: default sidebarCollapsed to true when the viewport is <768px, and make the auto-collapse effect use toggleSidebar(true) so repeated runs are idempotent.
Workaround we're running: setting localStorage.app_sidebar_collapsed = "true" for narrow screens in a script before the bundle boots. (Gotcha for anyone reproducing: that script runs before the viewport meta is parsed, so window.innerWidth still reports iOS's legacy 980px layout viewport — screen.width must be used.)
Steps to reproduce
- Self-host CE v1.3.1, log in on an iPhone (or Playwright WebKit with an iPhone descriptor).
- Open any project's work-items page → error boundary (Bug 1).
- Apply a
requestIdleCallback polyfill so the page renders → tap any kanban card → nothing happens (Bug 2).
Repro harness (Playwright):
import { webkit, devices } from 'playwright';
const browser = await webkit.launch();
const ctx = await browser.newContext({ ...devices['iPhone 13'] });
// + authenticated session cookie
const page = await ctx.newPage();
page.on('pageerror', e => console.log('PAGEERROR:', e.message));
await page.goto('https://<instance>/<workspace>/projects/<id>/issues/');
await page.waitForTimeout(10000);
// Bug 1: pageerror = requestIdleCallback TypeError
// Bug 2 (after polyfill): tap times out with "subtree intercepts pointer events" from #main-sidebar
await (await page.$('[id^="issue-"]')).tap({ timeout: 10000 });
Environment
Self-hosted CE v1.3.1 (docker compose deploy). Reproduced on real iPhone Safari (iOS 26) and with Playwright WebKit (iPhone 13 device profile). Desktop browsers are unaffected (both bugs are WebKit/viewport-specific).
Two independent bugs make the v1.3.1 web app effectively unusable on iOS. Root-cause analysis for both is included below (file/line refs are against the v1.3.1 tag).
Bug 1 — unguarded
requestIdleCallbackcrashes every workspace page on WebKitSymptom: any workspace page (kanban, list, …) immediately shows the "🚧 Looks like something went wrong!" error boundary.
Console:
Root cause: Safari/WebKit still does not ship
requestIdleCallback(it remains behind an experimental flag), and a layout component rendered by workspace pages callswindow.requestIdleCallback(...)unguarded, throwing during render.Suggested fix: feature-guard the call (
window.requestIdleCallback ?? setTimeoutfallback) or add a polyfill to the app entry.Workaround we're running: a
setTimeout-based polyfill injected intoindex.htmlahead of the bundle — with it, the pages render fine, which confirms this is the only fatal error on the path.(While debugging we also consistently see React hydration errors #418/#423 on the prerendered shell in WebKit — non-fatal since React recovers, but noisy and possibly related to Bug 2's state confusion.)
Bug 2 — on <768px viewports the expanded sidebar overlays the entire board and swallows every tap
Symptom: tapping any kanban card does nothing — users report "opening/modifying a card never loads". The peek overlay itself is healthy: programmatically force-clicking a card through the overlay opens it normally.
Evidence: Playwright cannot deliver a tap to any card:
Root cause chain (v1.3.1):
apps/web/core/components/sidebar/resizable-sidebar.tsx(~line 185): when not collapsed the sidebar renderstranslate-x-0 opacity-100, plusabsolutewhenisMobile— i.e. a full-height z-20 overlay on phones.apps/web/core/components/sidebar/sidebar-wrapper.tsx(~line 46):if (windowSize[0] < 768 && !sidebarCollapsed) toggleSidebar(). On project/workspace issue pages this component's effect does not end up collapsing the sidebar (and a syntheticresizeevent doesn't either), so the overlay stays up.toggleSidebar()(toggle) instead oftoggleSidebar(true)(set): if it runs more than once (two wrapper instances / re-mounts), the state flips collapsed → expanded again. We observedapp_sidebar_collapsedbeing written"true"then"false"during a single boot on a fresh profile.store-wrapper.tsx(~line 48) only applieslocalStorage.app_sidebar_collapsedwhen it exists, and there is no width-aware default — so a fresh mobile visitor always starts expanded/overlaying.Suggested fix: default
sidebarCollapsedtotruewhen the viewport is <768px, and make the auto-collapse effect usetoggleSidebar(true)so repeated runs are idempotent.Workaround we're running: setting
localStorage.app_sidebar_collapsed = "true"for narrow screens in a script before the bundle boots. (Gotcha for anyone reproducing: that script runs before theviewportmeta is parsed, sowindow.innerWidthstill reports iOS's legacy 980px layout viewport —screen.widthmust be used.)Steps to reproduce
requestIdleCallbackpolyfill so the page renders → tap any kanban card → nothing happens (Bug 2).Repro harness (Playwright):