diff --git a/components/layout/__tests__/sidebar-rail-peek-hover.test.tsx b/components/layout/__tests__/sidebar-rail-peek-hover.test.tsx
index 444f6de8c..5e65bfbc5 100644
--- a/components/layout/__tests__/sidebar-rail-peek-hover.test.tsx
+++ b/components/layout/__tests__/sidebar-rail-peek-hover.test.tsx
@@ -1,4 +1,4 @@
-import { render } from '@testing-library/react';
+import { render, screen, cleanup } from '@testing-library/react';
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import type { Mailbox } from '@/lib/jmap/types';
@@ -51,6 +51,24 @@ describe('Mountain View rail peek', () => {
const peek = (container: HTMLElement) => container.querySelector('[data-mv-rail-peek]');
+ it('shows folder names in the drawer of a narrow window, even when collapsed on a wider one', () => {
+ const matchMedia = window.matchMedia;
+ window.matchMedia = ((query: string) => ({
+ matches: query.includes('64rem'), media: query, addEventListener() {}, removeEventListener() {},
+ })) as never;
+ try {
+ render();
+ expect(screen.getByText('News')).toBeTruthy();
+ } finally {
+ window.matchMedia = matchMedia;
+ }
+ });
+
+ it('keeps the icon rail on a wide window', () => {
+ render();
+ expect(screen.queryByText('News')).toBeNull();
+ });
+
it('peeks on hover by default', () => {
const { container } = render();
fire.mouseEnter(container.firstElementChild!);
diff --git a/components/layout/sidebar.tsx b/components/layout/sidebar.tsx
index 027776414..e525f3737 100644
--- a/components/layout/sidebar.tsx
+++ b/components/layout/sidebar.tsx
@@ -61,6 +61,7 @@ import { Mailbox } from "@/lib/jmap/types";
import { useContextMenu } from "@/hooks/use-context-menu";
import { useLongPress } from "@/hooks/use-long-press";
import { useMediaQuery } from "@/hooks/use-media-query";
+import { usePaneSize } from "@/hooks/use-pane-size";
import { IconButton } from "@/components/ui/icon-button";
import { MailboxContextMenu, type MailboxContextTarget, type MailboxNotificationActions } from "./mailbox-context-menu";
import { useAccountStore } from '@/stores/account-store';
@@ -1166,7 +1167,12 @@ function SidebarImpl({
// list behind it.
const [railHovered, setRailHovered] = useState(false);
const hoverExpanded = mvShell && sidebarCollapsed && railHovered;
- const isCollapsed = sidebarCollapsed && !hoverExpanded;
+ // The rail is a desktop thing. Below that the sidebar is a drawer, opened to
+ // read the folder names, whatever the collapse button last said on a wider window.
+ const paneWidth = usePaneSize();
+ const narrowWindow = useMediaQuery('(width < 64rem)');
+ const isDrawer = paneWidth !== null ? paneWidth < 1024 : narrowWindow;
+ const isCollapsed = sidebarCollapsed && !hoverExpanded && !isDrawer;
const { primaryIdentity: _primaryIdentity, activeAccountId } = useAuthStore(useShallow((state) => ({ primaryIdentity: state.primaryIdentity, activeAccountId: state.activeAccountId })));
const [expandedFolders, setExpandedFolders] = useState>(new Set());
const [expandedTags, setExpandedTags] = useState>(new Set());