skip to content

In Vue Router 5, how do named views show a mail list and message detail side by side, and how do they differ from nesting?

level: middleimportance: should knowfreq 38%

answer

  1. components with an s
  2. default is the unnamed view
  3. RouterView name prop
  4. siblings at one depth
  5. a missing view renders nothing

basics

~20 s

A record's components map (default, detail, ...) fills several RouterViews at the same depth, each selected by its name prop; nested routes instead stack one view inside another. Views without a component for the route render nothing.

solid answer

~40 s

A record can set `components` (with an s) instead of `component`: `{ path: '/mail/:folder/:messageId?', components: { default: MessageList, detail: MessageDetail } }`. The layout renders `<RouterView />`, whose name is `default`, and `<RouterView name="detail" />`; each picks its component from the matched record by name. Named views are **siblings at one depth**, filled by one record, while nested routes are **levels**, filled by a parent and a child. A `RouterView` whose name has no entry in the matched record renders nothing, which lets a route omit the detail pane. Nested layouts can use named views too; the named `RouterView` then sits inside the parent component. With named views, the `props` option also becomes a per-view map.

code

ts · 14 lines
ts
const routes = [
  {
    path: '/mail',
    component: () => import('@/views/mail/MailLayout.vue'), // default + detail RouterViews
    children: [
      { path: ':folder', components: { default: MessageList } },
      {
        path: ':folder/:messageId',
        components: { default: MessageList, detail: MessageDetail },
        props: { default: true, detail: true },
      },
    ],
  },
]

go deeper

for a junior

Know the components map with a default key and the name prop on RouterView.

for a middle

Contrast named views with nested routes and explain what renders when a view has no component.

for a senior

Combine named views with nested layouts, place each named RouterView at the right depth, and reason about which panes remount.

for a principal

Choose between peer panes and nested layouts for complex screens so URLs, state lifetimes and layout ownership line up.

## Several outlets, one match A route record normally declares one `component`. With **named views** it declares `components`, an object mapping view names to components: ```ts { path: '/mail/:folder/:messageId?', components: { default: MessageList, detail: MessageDetail, }, } ``` The layout places one `RouterView` per name: ```vue <template> <div class="mail"> <MailFolders /> <RouterView /> <RouterView name="detail" /> </div> </template> ``` - A `RouterView` without a `name` prop is the `default` view. - Each `RouterView` looks up its own name in the matched record's `components` map. - The spelling matters: `components` with an **s** holds the map; `component` holds a single component for the default view. ## Named views versus nested routes | | Named views | Nested routes | |---|---|---| | Declared with | `components: { default, detail }` | `children: [...]` | | Layout | siblings side by side | one view inside another | | Records matched | one record fills several views | one record per level | | RouterViews | several at the same depth, different names | one per depth | | URL | one path for all panes | parent path plus child path | The two combine. A mail layout can be a parent route whose component holds named `RouterView`s, and its children can each declare `components` for those names. The docs' settings example does this: a child renders `default` and `helper` views inside the parent's component. ## When a view has no component If the matched record has no entry for a `RouterView`'s name, that view renders **nothing**. With the slot API, the slot still runs, with `Component` undefined. This is useful: - A route `/mail/:folder` can declare only `default`, leaving the detail pane empty until a message is chosen. - A route `/mail/:folder/:messageId` declares both. - A wide layout can show an extra `aside` view only on routes that define one. A typo in the name renders nothing too, without an error, so it is worth a test. ## What remounts in the mail client With one record `/mail/:folder/:messageId?` declaring both views: 1. Choosing another message changes only `messageId`. Both views keep the same components, so both instances are **reused**; each must watch its params. 2. Switching folders also reuses both; the list reloads by watching `folder`. With separate records, `/mail/:folder` declaring `default` only and `/mail/:folder/:messageId` declaring both, opening the first message mounts `MessageDetail` while the list component is reused, because the default view renders the same component under both records. ## Named views in nested layouts - The named `RouterView` must live at the depth where the record that declares the name renders. A `detail` view declared by a child record needs a `<RouterView name="detail" />` inside the parent's component, not in `App.vue`. - Per-view props need a map: `props: { default: true, detail: true }`. A bare `true` applies to every view. - A route that declares a component for a view name that no `RouterView` renders simply never shows it. ## One URL drives every pane Because all named views come from one matched route, the URL is the single source of truth for the whole screen: - A deep link to `/mail/inbox/42` reproduces both the list and the open message. - The browser's back button after opening a message returns to `/mail/inbox`, whose record declares no `detail` view, so the pane closes by itself. - Links and programmatic navigation only ever change the URL; no pane is shown or hidden by hand. - On narrow screens the layout can hide one of the `RouterView`s with CSS or a condition, while the route table stays the same. ## When to choose which - Choose **named views** when panes are peers that change together with one URL: list and detail, main and sidebar, content and contextual help. - Choose **nested routes** when one pane owns the others and should persist while they change: a settings layout around its sections. - Mixing them is normal; the depth-and-name rule tells you which `RouterView` renders what.

  • The detail pane stays blank even on /mail/inbox/42. What would you check first?
    That the `RouterView name="detail"` sits at the depth where the record declaring `detail` renders: inside `MailLayout` for a child record, not in `App.vue`. Then check the spelling on both sides and that the record uses `components`, not `component`. A name mismatch renders nothing without an error.
  • Why would you not implement the detail pane as a nested child of the list route?
    Nesting makes the detail render inside the list component's own `RouterView`, which couples the detail to the list's markup and layout. Named views keep the panes as peers in the layout, which fits side-by-side panes that are laid out by the parent and change together.

A newspaper page template with labelled boxes: headline, main story, sidebar. Each day's edition (the matched route) says what goes in each labelled box; a box the edition leaves out stays blank, and nobody builds a second page inside the first.

saying these in an interview costs you the question

  • Named views are declared with a component option holding an object.
  • A RouterView without a name renders every named component.
  • A missing named component throws an error at navigation.
  • Named views and nested routes cannot be combined.
  • A named RouterView in App.vue can render a child record's named view.