| name | design-layout-navigation |
| description | Build the page structure and navigation of a full-stack Rails 8.1 Hotwire app — the application shell (layout + content regions, header/main/footer landmarks), primary navigation (top navbar, sidebar, or hybrid), breadcrumbs and active-state highlighting, responsive/mobile navigation, and pagination UX (Pagy). Menu-driven with a Recommended default per menu; detects the existing layout, nav, and pagination gem first, builds from design-foundations tokens and design-components primitives, and verifies the shell renders responsively with correct landmarks. Apply when creating the app layout, a navbar/sidebar, breadcrumbs, a responsive menu, or paginating a list. Web apps only. |
| metadata | {"owner":"rails-design","status":"stable"} |
| user-invocable | true |
| argument-hint | [shell-or-nav] |
design-layout-navigation
Purpose
Owns the page chrome: the application shell that wraps every page (the
<header>/<main>/<footer> landmarks, content regions, max-widths, sticky behavior),
the primary navigation (top navbar, sidebar, or both), breadcrumbs and
active-state highlighting, responsive navigation (the mobile menu), and the UX
of pagination (Pagy). It assembles the primitives from ../design-components/ using
tokens from ../design-foundations/, and leans on ../design-accessibility/ for
landmark, skip-link, and keyboard requirements. The Turbo/Stimulus plumbing behind a
mobile drawer or active-link controller is ../rails-hotwire/.
When to Apply
Use this skill when the task is:
- Building the application layout / shell (header, main, footer, content width, sticky header)
- A primary navigation bar or sidebar (or a hybrid)
- Breadcrumbs and highlighting the current page/section
- A responsive / mobile menu (hamburger → drawer/sheet)
- Pagination UX for a list/index (page links, per-page, infinite scroll entry point)
Do not use this skill when the task is:
- Tokens (colors/type/spacing) or theming → read
../design-foundations/SKILL.md
- The component primitives the nav is built from (buttons, menus) → read
../design-components/SKILL.md
- Interactive mechanics of a drawer/dropdown/infinite-scroll append → read
../design-interactions/SKILL.md (this skill owns the layout; that one owns the behavior)
- Routing / which controller renders what → read
../rails-controllers/SKILL.md
- Turbo/Stimulus wiring for the menu toggle → read
../rails-hotwire/SKILL.md
- Landmark/keyboard a11y rules in depth → read
../design-accessibility/SKILL.md
- An API-only app — no pages to lay out
Detect Before You Generate
grep -nE "api_only" config/application.rb
ls app/views/layouts/*.html.erb 2>/dev/null
grep -rlnE "<nav|role=\"navigation\"|navbar|sidebar" app/views 2>/dev/null | head
grep -E "pagy|kaminari|will_paginate" Gemfile.lock 2>/dev/null
grep -rnE "<main|<header|<footer|yield" app/views/layouts 2>/dev/null
grep -E "daisyui|flowbite" Gemfile.lock package.json 2>/dev/null
- Match the existing layout. If
application.html.erb already defines the shell,
extend it — don't create a parallel layout.
- Use the installed pagination gem.
pagy / kaminari / will_paginate in the
lockfile → use it; don't add a second.
- If a UI kit is present, use its navbar/drawer/menu classes rather than hand-building.
Menu
Three menus via AskUserQuestion; defaults marked Recommended. Ask unless detected.
Layout shell
| Option | One-line trade-off | Deep dive |
|---|
| App-wide layout + content regions (Recommended) | One application.html.erb with header/main/footer + yield and named yields; consistent chrome everywhere. | app-shell.md |
| Per-section layouts | Separate layouts (e.g. marketing vs app vs admin); flexible, more to keep in sync. | app-shell.md |
Primary navigation
| Option | One-line trade-off | Deep dive |
|---|
| Top navbar (Recommended) | Horizontal bar; familiar, space-efficient, great for ≤7 top items and marketing+app. | navbar.md |
| Sidebar | Vertical nav; scales to many sections/nested groups, ideal for dashboards/admin. Costs horizontal space. | sidebar.md |
| Hybrid (navbar + sidebar) | Top bar for global actions + sidebar for sections; powerful, more layout complexity. | sidebar.md |
Pagination
| Option | One-line trade-off | Deep dive |
|---|
| Pagy (Recommended) | Fastest, lightest pagination gem; minimal memory, Tailwind/daisyUI-friendly helpers, keyset/cursor support. | pagination-pagy.md |
| Kaminari / will_paginate | Established, more built-in view scaffolding; heavier than Pagy. Use if already installed. | pagination-pagy.md |
| Infinite scroll (Turbo Streams) | Append-on-scroll for feeds; great for discovery, worse for findability/SEO. Mechanics in design-interactions. | pagination-pagy.md |
Decision Flow
- Shell: start with one app-wide layout and named content regions (sidebar slot,
page title, actions). Split into per-section layouts only when marketing/app/admin
truly diverge — keep shared partials to avoid drift.
- Navigation: top navbar for most apps and any marketing surface; sidebar when
there are many sections or nested groups (dashboards, admin); hybrid for large apps
that need both global actions and deep section nav. Don't put 12 items in a top bar.
- Active state is a usability essential — highlight the current section so users always
know where they are (breadcrumbs-active-states.md).
Add breadcrumbs when hierarchy is more than two levels deep.
- Responsive: every nav needs a mobile form — usually a hamburger that opens a
drawer/sheet. The layout is here; the open/close behavior is
../design-interactions/ (responsive-nav.md).
- Pagination: Pagy for speed/footprint unless another gem is already installed;
infinite scroll only for feed-style discovery (and keep a paginated/SEO fallback).
- Landmarks + skip link come from
../design-accessibility/ — <nav>, <main id>,
and a skip-to-content link are non-negotiable.
Problem → Reference
| Task | Read |
|---|
| Build the app shell: layout, header/main/footer, content width, sticky header | references/app-shell.md |
| Top navbar: structure, dropdowns, responsive collapse | references/navbar.md |
| Sidebar / hybrid: collapsible, nested groups, dashboard layout | references/sidebar.md |
Breadcrumbs + active/current highlighting (current_page?, aria-current) | references/breadcrumbs-active-states.md |
| Responsive navigation: hamburger, mobile drawer, breakpoints | references/responsive-nav.md |
| Pagination UX with Pagy (helpers, styling, keyset, infinite-scroll entry) | references/pagination-pagy.md |
Verify
The shell is "done" when it renders with correct landmarks, highlights the current
section, and works on a phone:
bin/rails server -d && sleep 3
curl -fsS localhost:3000/ -o /tmp/p.html -w "root=%{http_code}\n"
grep -qE "<main|role=\"main\"" /tmp/p.html && echo "✓ <main> landmark present"
grep -qiE 'skip to content|href="#main"' /tmp/p.html && echo "✓ skip link present"
grep -qE 'aria-current' /tmp/p.html && echo "✓ active-state marker present"
kill "$(cat tmp/pids/server.pid)"
Resize to 375px and confirm the nav collapses to a usable mobile menu; Tab through and
confirm the skip link + landmark navigation work. Then route to ../design-interactions/
for the mobile-drawer behavior and ../design-accessibility/ for the full landmark/keyboard audit.