ClaudeExpo2026/07/11 14:30

Building balanced mobile layouts: nesting tabs and drawers with Expo Router

要点だけを先に読めるように短く再構成したセクションです。

元記事

Quick Digest

要約

要点だけを先に読めるように短く再構成したセクションです。

claudeja

Building balanced mobile layouts: nesting tabs and drawers with Expo Router の要約

Key Points

  • ポイント1: You've got a bottom tab bar working.
  • ポイント2: Then a mockup lands with a hamburger menu that slides out over the tabs: a workspace switcher, settings, a link to support.
  • ポイント3: Now you need both navigation patterns at once, one nested inside the other, without the drawer swipe fighting your image carousel or the tab state resetting every time someone open

Summary

この記事は 2026-07-11 に公開された「Building balanced mobile layouts: nesting tabs and drawers with Expo Router」の内容を日本語で簡潔にまとめたものです。

Key Points

  • ポイント1: You've got a bottom tab bar working.
  • ポイント2: Then a mockup lands with a hamburger menu that slides out over the tabs: a workspace switcher, settings, a link to support.
  • ポイント3: Now you need both navigation patterns at once, one nested inside the other, without the drawer swipe fighting your image carousel or the tab state resetting every time someone open

Full Translation

翻訳

原文の流れを保ったまま読める翻訳セクションです。

claudeja

Building balanced mobile layouts: nesting tabs and drawers with Expo Router(原文タイトル)

概要

公開日: 2026-07-11 翻訳生成に失敗したため、原文をそのまま保存しています。

原文

You've got a bottom tab bar working. Then a mockup lands with a hamburger menu that slides out over the tabs: a workspace switcher, settings, a link to support. Now you need both navigation patterns at once, one nested inside the other, without the drawer swipe fighting your image carousel or the tab state resetting every time someone opens the menu. A persistent bottom tab bar paired with a global sidebar drawer is a common pattern in cross-platform apps. Nest those navigation trees carelessly, though, and you invite performance overhead and gesture conflicts. With Expo Router, you map these flows directly onto a file-system directory. Your code stays modular and maintainable, and the native navigation components still do the work underneath. I shared a demo of this on twitter and the Expo team reached out about sharing my process. Hopefully by the end of this post you'll have a drawer wrapping a tab navigator, plus the theming and gesture handling that keep the whole thing from feeling janky. Architectural fit: when to nest drawers and tabs Combining navigation patterns is powerful, but it shouldn't be your default. Before writing any code, work out whether your app's UX actually benefits from a dual-navigation hierarchy. Three rough cases: - Flat navigation (3 to 5 high-level screens with isolated paths): use pure bottom tabs. A side drawer here just adds cognitive load and visual clutter. - Contextual isolation (a multi-tab workspace that needs omnipresent utilities like org switching or support): nest the tab navigator inside an outer drawer container. - Deep-linked workflows (transaction-heavy dashboards where users bounce between deep sub-routes): reach for native stack navigation with context-driven visibility instead. Architectural tradeoffs and limitations Clean file-system layout paths ease structural complexity, but a few constraints are worth knowing about: - State synchronization: Passing shared global state or active user details from a standalone drawer route (like a detached settings.tsx) down into the nested tab context takes deliberate context scoping, or an external store. - Platform gesture conflicts: Side-swipe drawer gestures can conflict with horizontal elements inside your tabs, like swipeable carousels or swipe-to-delete lists. Restricting swipeEdgeWidth keeps those interactions predictable. The core architecture To keep navigation state unified, your project directory should mirror your layout tree. Instead of a centralized routing config file, Expo Router lets you declare the view hierarchy directly with folder grouping semantics like (drawer) and (tabs). app/ ├── (drawer)/ │ ├── _layout.tsx # Outermost navigation wrapper (configures side drawer) │ ├── (tabs)/ │ │ ├── _layout.tsx # Inner layout (configures persistent bottom tabs) │ │ ├── index.tsx # Home dashboard screen │ │ ├── explore.tsx # Explore feed screen │ │ ├── notifications.tsx │ │ └── profile.tsx # User profile screen │ └── settings.tsx # Standalone global route accessed via drawer └── _layout.tsx # Root orchestration and app lifecycle entry point 1. Root orchestration (app/_layout.tsx) The root file is where the app lifecycle starts. It manages the native splash screen and sets up global context providers, so runtime configuration is in place before any child route renders. import 'react-native-gesture-handler'; import React, { useState } from 'react'; import { Slot } from 'expo-router'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { StyleSheet } from 'react-native'; import * as ExpoSplashScreen from 'expo-splash-screen'; import { ThemeProvider } from '../src/context/ThemeContext'; import SplashScreenView from '../src/screens/SplashScreen'; // Prevent splash screen from auto-hiding before initialization checks finish ExpoSplashScreen.preventAutoHideAsync(); export default function RootLayout() { const [appIsReady, setAppIsReady] = useState