Skip to content

[bug]: use-mobile.ts uses pixel logic, causing UI state de-sync with Tailwind CSS rem breakpoints #12393

Open

Description

@catdoy0

Describe the bug

This bug happens because shadcn's Sidebar component directly mixes Tailwind v4's relative layout modifiers with the hook's absolute pixel logic:

// Inside shadcn's Sidebar component code:
className="group peer hidden text-sidebar-foreground md:block"

In Tailwind v4, the md: modifier is evaluated dynamically as a relative size (48rem).

If a user scales their default browser font size up to 24px, Tailwind's md: media query dynamically targets 1152px (48rem × 24px). If the browser window is at 1000px, Tailwind hides the desktop layout container completely via hidden md:block.

However, because use-mobile.ts is hardcoded to 768px, the React logic evaluates isMobile as false. The component completely skips rendering the mobile <Sheet>, and attempts to render the desktop container which Tailwind has hidden. The sidebar completely disappears from the layout, and the SidebarTrigger button stops functioning entirely between 768px and 1152px because it is stuck trying to toggle a hidden desktop layout instead of opening the mobile drawer.

works fine if browser font size is using recommended size.

Affected component/components

sidebar, use-mobile

How to reproduce

  1. Use a standard layout utilizing the shadcn Sidebar component (which implements use-mobile.ts).
  2. Open browser settings and change the Default Font Size from Medium (16px) to Very Large (24px).
  3. Sidebar correctly goes into mobile mode at 1152px meanwhile cant open it using SidebarTrigger until it hits below 768px

Codesandbox/StackBlitz link

https://github.com/shadcn-ui/ui/blob/main/apps/v4/hooks/use-mobile.ts

Logs

System Info

- "shadcn": "^4.21.4",
-  "tailwindcss": "^4.3.3",
- chrome Font size Very Large 24px

Before submitting

  • I've made research efforts and searched the documentation
  • I've searched for existing issues

Activity

  1. shaurya-10000 commented on Oct 20, 2026

    @shaurya-10000

    Hi, I’d like to take this. I can reproduce it with the browser font size set to 24px. Changing the media query to rem isn’t enough on its own, because onChange and the initial state still compare window.innerWidth to the pixel breakpoint. My plan is to use a (width < 48rem) query and read mql.matches, keeping the mobileBreakpoint param in px so existing callers aren’t affected. Happy to open a PR if that approach works for you.

  2. shaurya-10000 commented on Oct 20, 2026

    @shaurya-10000

    I've opened a PR for this: #12397

    Besides switching the media query to rem, it also reads mql.matches instead of window.innerWidth, since the state was derived from innerWidth before. Happy to adjust if you'd prefer a different approach.

  3. added a commit that references this issue on Oct 20, 2026
    2e7ec91
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions