fix(web): respect iOS safe areas across mobile chrome & other mobile layout fixes#2392

merged5
main
GitHub fork: fix/mobile-safe-area
openedApr 28, 2026byJjappyjan
View on GitHubTwo-way sync enabledPR last imported 5d ago

Summary

`viewport-fit=cover` was already in place, but no element in the codebase honored `env(safe-area-inset-*)`. On iPhone the chat header / hamburger sat under the Dynamic Island, the composer hid behind the home indicator, and the mobile sidebar drawer ran under the camera in landscape.

Approach

  • Define four `@utility` classes (`pt-safe`, `pb-safe`, `pl-safe`, `pr-safe`) in `apps/web/src/index.css`. Each resolves to `max(env(safe-area-inset-*), 0px)`, so the value is 0 on devices without safe areas โ€” desktop and Android are unaffected.
  • Apply the bare `*-safe` utilities on the mobile sidebar drawer's inner wrapper, where there's no other padding to combine with.
  • For the chat top bar (`ChatView.tsx`) and the composer wrapper (`ChatView.tsx`), use inline `pt-[calc(env(safe-area-inset-top)+0.5rem)]` etc. The existing `px-3 sm:px-5` base padding has to be preserved on devices without safe areas; bare `pl-safe`/`pr-safe` would override those due to Tailwind's specificity-collision resolution and zero them out.
  • The Electron branch in `ChatView.tsx`'s header is left as-is โ€” it already uses its own `wco:h-[env(titlebar-area-height)]` sizing.

Test plan

  • iPhone portrait: chat title and hamburger fully visible below Dynamic Island
  • iPhone portrait: composer + send button sit above home indicator
  • iPhone landscape: sidebar drawer not clipped by camera
  • iPhone: open sidebar โ€” its content not under the island
  • Desktop / non-iOS mobile: no visible padding change

Screenshots / video

Note

Fix iOS safe area insets and mobile layout across the web app

  • Adds safe-area-aware CSS utilities (pt-safe, pb-safe, etc.) in index.css and applies them to the mobile sidebar and input bar in ChatView
  • Switches mobile route containers from h-dvh to h-svh (with md:h-dvh) for layout stability when browser chrome appears/disappears
  • Adds interactive-widget=resizes-content to the viewport meta tag so on-screen keyboards resize content instead of overlaying it
  • Introduces a MobileRunContextSelector in BranchToolbar.tsx that consolidates environment and workspace selectors into a single menu button on small screens
  • Fixes composer focus to use preventScroll: true so focusing the input does not scroll the page

Macroscope summarized 681d312.


Note

Medium Risk Medium risk because it changes global viewport/height/overflow CSS and mobile safe-area padding across core chat routes, which could cause regressions in scrolling or layout on non-iOS browsers.

Overview Improves mobile/iOS layout by honoring safe areas and reducing viewport chrome/keyboard layout issues. Adds interactive-widget=resizes-content to the viewport meta and introduces pt-safe/pb-safe/pl-safe/pr-safe utilities plus global svh/overflow adjustments to better support edge-to-edge rendering.

Updates chat routes and ChatView spacing to account for env(safe-area-inset-*), moves the BranchToolbar into the input-area wrapper, and adds a mobile-only consolidated run-context menu for environment/workspace selection. Also tweaks sidebar mobile sheet padding for safe areas, uses h-svh on mobile with md:h-dvh, and prevents editor focus from auto-scrolling while hiding OpenInPicker in remote environments.

Reviewed by Cursor Bugbot for commit 681d3127c6dcc891102fa6faa8ebf1c7571e6c94. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved layout spacing and alignment on the chat interface and mobile navigation sidebar for devices with notches, Dynamic Island, and other display safe-area features, ensuring proper positioning across all modern mobile devices.

Open in Devin Review

Checks

9 successful ยท 2 neutral ยท 1 skipped
All checks passed
681d312
Synced from GitHub
๐Ÿ“ Walkthrough

Walkthrough

Adds safe-area inset CSS utility classes and applies them across layout components (header, input bar, sidebar) to properly reserve space for device notches, Dynamic Island, and home indicator regions on iOS.

Changes

Cohort / File(s)Summary
Safe-Area CSS Utilities
apps/web/src/index.css
Introduces four new utility classes (pt-safe, pb-safe, pl-safe, pr-safe) using CSS env(safe-area-inset-*) variables for device-aware spacing.
Layout Component Updates
apps/web/src/components/ChatView.tsx, apps/web/src/components/ui/sidebar.tsx
Applies safe-area-aware padding to header, input bar, and mobile sidebar container; replaces fixed padding with computed values based on safe-area insets and conditional logic.

Estimated code review effort

๐ŸŽฏ 2 (Simple) | โฑ๏ธ ~10 minutes

Poem

๐Ÿฐ A notch-aware warren, at last! Safe spaces emerge from the CSS vast, Where padding respects each device's decree, Dynamic Islands and notches now flee, The sidebar hops safely, with spacing so wise, No content lost under those iOS skies! โœจ

๐Ÿšฅ Pre-merge checks | โœ… 4 | โŒ 1

โŒ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverageโš ๏ธ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
โœ… Passed checks (4 passed)
Check nameStatusExplanation
Linked Issues checkโœ… PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkโœ… PassedCheck skipped because no linked issues were found for this pull request.
Title checkโœ… PassedThe title clearly and specifically describes the main change: respecting iOS safe areas in mobile layouts, which directly corresponds to the PR's primary objective of fixing UI element obscuration on iOS devices.
Description checkโœ… PassedThe PR description comprehensively covers all required template sections with clear explanations of changes, rationale, test plan, and includes a screenshot.

โœ๏ธ Tip: You can configure your own custom pre-merge checks in the settings.

โœจ Finishing Touches
๐Ÿงช Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

โค๏ธ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

apps/web/src/components/ui/sidebar.tsxline 248Outdated ยท f9955bbOpen thread
โ€ฆโ€ฆ@@ -245,7 +245,7 @@ function Sidebar({
246246 <SheetDescription>Displays the mobile sidebar.</SheetDescription>
247247 </SheetHeader>
248- <div className="flex h-full w-full flex-col">{children}</div>
248+ <div className="flex h-full w-full flex-col pb-safe pl-safe pt-safe">{children}</div>
MmacroscopeappBoton line 248Apr 28, 2026

๐ŸŸข Low ui/sidebar.tsx:248

The safe-area padding classes pb-safe pl-safe pt-safe are applied unconditionally on line 248, using pl-safe (padding-left) regardless of the side prop. When side="right", the sidebar slides in from the right edge and needs pr-safe (padding-right) to avoid content being obscured by right-side notches in landscape orientation. Consider conditionally applying pl-safe for left sidebars and pr-safe for right sidebars.

โœ… Resolved in 62ee8224bf19050910f5d66b2928e23df909b2ab

Added 1 commit

  • fix(web): respect iOS safe areas across mobile chrome62ee822
Synced from GitHub
โœ… Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

CcoderabbitaiBotreviewed ยท 1 inline threadApr 28, 2026
Synced from GitHub

Actionable comments posted: 1

๐Ÿค– Prompt for all review comments with AI agents
1Verify each finding against the current code and only fix it if needed.
2
3Inline comments:
4In `@apps/web/src/index.css`:
5- Around line 65-76: The Stylelint config is flagging Tailwind v4's custom
6at-rule "@utility" in apps/web/src/index.css; update .stylelintrc.json to allow
7it by adding or merging a rule entry for "at-rule-no-unknown" that supplies an
8ignoreAtRules array including "utility" (and any other Tailwind at-rules you
9use), e.g. add "rules": { "at-rule-no-unknown": [true, { "ignoreAtRules":
10["utility"] }] } so the `@utility` declarations in index.css (padding-safe
11utilities) are not treated as unknown at-rules.
๐Ÿช„ Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

โ„น๏ธ Review info
โš™๏ธ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9fb2038b-732c-4a48-ac8c-83238e731845

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between dbebc387dd458dd7062380ccb862a5cdac7aba66 and 62ee8224bf19050910f5d66b2928e23df909b2ab.

๐Ÿ“’ Files selected for processing (3)
  • apps/web/src/components/ChatView.tsx
  • apps/web/src/components/ui/sidebar.tsx
  • apps/web/src/index.css
apps/web/src/index.csslines 65โ€“76Outdated ยท 62ee822Open thread
โ€ฆโ€ฆ@@ -58,6 +58,23 @@
73+}
74+@utility pr-safe {
75+ padding-right: max(env(safe-area-inset-right), 0px);
76+}
CcoderabbitaiBoton lines 65โ€“76Apr 28, 2026

โš ๏ธ Potential issue | ๐ŸŸ  Major

๐Ÿงฉ Analysis chain

๐Ÿ Script executed:

shell
1#!/bin/bash
2set -euo pipefail
3
4echo "== Stylelint config files =="
5fd -HI 'stylelint' .
6
7echo
8echo "== at-rule rule definitions / ignoreAtRules =="
9rg -n --iglob '*stylelint*' 'scss/at-rule-no-unknown|at-rule-no-unknown|ignoreAtRules|utility|theme|variant|custom-variant|source'
10
11echo
12echo "== package.json stylelint references =="
13rg -n '"stylelint"|stylelint' package.json

Repository: pingdotgg/t3code

Length of output: 157


๐Ÿ Script executed:

shell
1cat .stylelintrc.json

Repository: pingdotgg/t3code

Length of output: 1420


Stylelint config must be updated to allow Tailwind v4 @utility at-rules.

The current .stylelintrc.json extends stylelint-config-standard-scss without configuring ignoreAtRules for Tailwind v4's custom at-rules. The @utility declarations at Lines 65, 68, 71, and 74 are valid Tailwind v4 syntax but will be flagged as unknown at-rules by stylelint, blocking CI.

Update .stylelintrc.json to add exception rules:

Configuration fix
diff
1{
2 "extends": ["stylelint-config-standard-scss"],
3 "rules": {
4+ "scss/at-rule-no-unknown": [true, {
5+ "ignoreAtRules": ["theme", "variant", "custom-variant", "utility", "source"]
6+ }],
7 "selector-id-pattern": null,
8 ...
9 }
10}
๐Ÿงฐ Tools
๐Ÿช› Stylelint (17.9.0)

[error] 65-65: Unexpected unknown at-rule "@utility" (scss/at-rule-no-unknown)

(scss/at-rule-no-unknown)


[error] 68-68: Unexpected unknown at-rule "@utility" (scss/at-rule-no-unknown)

(scss/at-rule-no-unknown)


[error] 71-71: Unexpected unknown at-rule "@utility" (scss/at-rule-no-unknown)

(scss/at-rule-no-unknown)


[error] 74-74: Unexpected unknown at-rule "@utility" (scss/at-rule-no-unknown)

(scss/at-rule-no-unknown)

๐Ÿค– Prompt for AI Agents
1Verify each finding against the current code and only fix it if needed.
2
3In `@apps/web/src/index.css` around lines 65 - 76, The Stylelint config is
4flagging Tailwind v4's custom at-rule "@utility" in apps/web/src/index.css;
5update .stylelintrc.json to allow it by adding or merging a rule entry for
6"at-rule-no-unknown" that supplies an ignoreAtRules array including "utility"
7(and any other Tailwind at-rules you use), e.g. add "rules": {
8"at-rule-no-unknown": [true, { "ignoreAtRules": ["utility"] }] } so the `@utility`
9declarations in index.css (padding-safe utilities) are not treated as unknown
10at-rules.

This codebase has no Stylelint configuration:

  • No .stylelintrc* or stylelint.config.* file exists in the repo
  • No stylelint dependency in any package.json (root, apps/web, or any workspace)
  • .github/workflows/ci.yml runs bun run lint which is oxlint โ€” there is no Stylelint step

The proposed config update would create configuration for tooling that isn't installed. No change needed; CI is not blocked.

The PR description image shows a mobile app interface with a dark theme on an iPhone, displaying what appears to be a code editor/AI assistant. The status bar shows 23:46, and the UI demonstrates the safe-area issue this PR is fixing โ€” the bottom navigation controls sit near the home indicator area.


@jappyjan, you're absolutely right โ€” I apologize for the noise. The @utility errors were surfaced by a static analysis pass in the review pipeline (Stylelint 17.9.0), not by anything present in the actual codebase. Since the project has no Stylelint installation or configuration and CI lints exclusively via oxlint, no change is needed. I'll make note of this for future reviews.


โœ๏ธ Learnings added
1Learnt from: jappyjan
2Repo: pingdotgg/t3code PR: 2392
3File: apps/web/src/index.css:65-76
4Timestamp: 2026-04-30T08:21:39.389Z
5Learning: The pingdotgg/t3code repository does not use Stylelint. There is no `.stylelintrc*` or `stylelint.config.*` file and no `stylelint` dependency in any `package.json`. The lint step in CI (`.github/workflows/ci.yml`) runs `bun run lint` which invokes `oxlint`. Do not raise Stylelint-based findings for this repository.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Synced from GitHub

Approvability

Verdict: Needs human review

Mobile layout and safe-area adjustments with an unresolved review comment identifying a potential layout conflict between root padding and viewport height that could clip content on iOS devices. Human review recommended to verify the fix is complete.

You can customize Macroscope's approvability policy. Learn more.

Added 1 commit

  • Merge branch 'main' into fix/mobile-safe-area9d8052b

Added 1 commit

  • Fix mobile safe area and show new chat buttonf36ad13
.t33/caches/codex.jsonline 451Outdated ยท f36ad13Open thread
โ€ฆโ€ฆ@@ -0,0 +1,451 @@
448+ "continuation": {
449+ "groupKey": "codex:home:/Users/julius/.codex"
450+ }
451+}
Ccursor[bot]on line 451Apr 30, 2026

Local dev tool cache committed with personal data

High Severity

The entire .t33/ directory is a local development tool's cache and user data that got committed because .gitignore only excludes .t3 (not .t33). These files contain personal data including julius@ping.gg, authentication details, local filesystem paths (/Users/julius/...), and an environment UUID. The userdata/ directory also contains a secrets/ folder and SQLite database files. None of this is related to the PR's iOS safe-area fix.

Additional Locations (2)

Reviewed by Cursor Bugbot for commit f36ad13f14ed17634fde25958ec4816aaa131dde. Configure here.

Added 1 commit

  • Remove local T33 cache and userdata artifactsb267430
Ccursor[bot]reviewed ยท 1 inline threadApr 30, 2026
Synced from GitHub

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

โŒ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b2674308e3c8168d7c07a12f0e5dc81b7bf57675. Configure here.

apps/web/src/index.cssline 178Outdated ยท b267430Open thread
โ€ฆโ€ฆ@@ -138,19 +154,28 @@ body {
152175 overflow-x: clip;
176+ overflow-y: hidden;
153177 overscroll-behavior-y: none;
178+ padding-top: max(env(safe-area-inset-top), 0px);
Ccursor[bot]on line 178Apr 30, 2026

Root padding-top conflicts with SidebarProvider absolute viewport height

Medium Severity

#root applies padding-top: max(env(safe-area-inset-top), 0px) which reduces its content area, while SidebarProvider uses h-dvh! (an absolute viewport unit). On iOS devices with safe areas, the SidebarProvider's height equals the full dynamic viewport, but it starts below the root's padding โ€” causing it to overflow the parent's content box by exactly env(safe-area-inset-top) pixels. Since #root has overflow-y: hidden, the bottom of the layout gets clipped. This manifests when dvh approaches the available content area (e.g., standalone/Add-to-Home-Screen mode, or when Safari's URL bar fully collapses), potentially hiding the bottom portion of the composer and branch toolbar.

Additional Locations (1)

Reviewed by Cursor Bugbot for commit b2674308e3c8168d7c07a12f0e5dc81b7bf57675. Configure here.

Added 1 commit

  • Show branch toolbar selectors on mobile681d312