Drawer

Renders a drawer with a header, body, and footer slot.

Read more Read less

All slots are optional, and you can render any content in them. If you want to use the drawer as a sidebar, you can use the vertical_nav/1 and vertical_nav_section/1 components.

Maturity: Developing

Usage

Minimal example:

<.drawer id="drawer">
  <:body>Content</:body>
</.drawer>

With all slots:

<.drawer id="drawer">
  <:header>Doggo</:header>
  <:body>Content at the top</:body>
  <:footer>Content at the bottom</:footer>
</.drawer>

With navigation and sections:

<.drawer id="drawer">
  <:header>
    <.link navigate={~p"/"}>App</.link>
  </:header>
  <:body>
    <.vertical_nav id="main-nav" label="Main">
      <:item>
        <.link navigate={~p"/dashboard"}>Dashboard</.link>
      </:item>
      <:item>
        <.vertical_nav_nested id="content-nav">
          <:title>Content</:title>
          <:item current_page>
            <.link navigate={~p"/posts"}>Posts</.link>
          </:item>
          <:item>
            <.link navigate={~p"/comments"}>Comments</.link>
          </:item>
        </.vertical_nav_nested>
      </:item>
    </.vertical_nav>
    <.vertical_nav_section id="search">
      <:title>Search</:title>
      <:item><input type="search" placeholder="Search" /></:item>
    </.vertical_nav_section>
  </:body>
  <:footer>
    <.vertical_nav id="user-nav" label="User menu">
      <:item>
        <.link navigate={~p"/settings"}>Settings</.link>
      </:item>
      <:item>
        <.link navigate={~p"/logout"}>Logout</.link>
      </:item>
    </.vertical_nav>
  </:footer>
</.drawer>

Semantics

With a header, the drawer renders role="complementary", named by the header. Set role to choose another landmark:

  • role="navigation" for a drawer that is the site navigation. The header still names it.
  • role={nil} for a drawer that holds a vertical_nav/1, which is a navigation landmark of its own. The page then has no complementary landmark around it.

Without a header, the drawer is no landmark unless you set role, and you name it with aria-label. With a header, the header names the drawer, and an aria-label has no effect.

Page content sits beside the drawer.

<div style="display: flex; align-self: stretch; block-size: 32rem">
  <div style="inline-size: 16rem; flex: none">
    <.drawer id="drawer-single-default">
      <:header>
        <Phoenix.Component.link navigate="/">Pet Clinic</Phoenix.Component.link>
      </:header>
      <:body>
        <.vertical_nav id="default-main-nav" label="Main">
          <:item>
            <Phoenix.Component.link navigate="/dashboard">
              Dashboard
            </Phoenix.Component.link>
          </:item>
          <:item>
            <.vertical_nav_nested id="default-main-nav-content">
              <:title>Content</:title>
              <:item current_page>
                <Phoenix.Component.link navigate="/posts">
                  Posts
                </Phoenix.Component.link>
              </:item>
              <:item>
                <Phoenix.Component.link navigate="/comments">
                  Comments
                </Phoenix.Component.link>
              </:item>
            </.vertical_nav_nested>
          </:item>
        </.vertical_nav>
        <.vertical_nav_section id="default-search">
          <:title>Search</:title>
          <:item><input type="search" placeholder="Search" aria-label="Search" /></:item>
        </.vertical_nav_section>
      </:body>
      <:footer>
        <.vertical_nav id="default-user-menu" label="User menu">
          <:item>
            <Phoenix.Component.link navigate="/settings">
              Settings
            </Phoenix.Component.link>
          </:item>
          <:item>
            <Phoenix.Component.link navigate="/logout">
              Logout
            </Phoenix.Component.link>
          </:item>
        </.vertical_nav>
      </:footer>
    </.drawer>
  </div>
  <p style="min-inline-size: 0; padding: 1rem">Page content sits beside the drawer.</p>
</div>

Page content sits beside the drawer.

<div style="display: flex; align-self: stretch; block-size: 32rem">
  <div style="inline-size: 16rem; flex: none">
    <.drawer id="drawer-single-without-header">
      <:body>
        <.vertical_nav id="without-header-main-nav" label="Main">
          <:item>
            <Phoenix.Component.link navigate="/dashboard">
              Dashboard
            </Phoenix.Component.link>
          </:item>
          <:item>
            <.vertical_nav_nested id="without-header-main-nav-content">
              <:title>Content</:title>
              <:item current_page>
                <Phoenix.Component.link navigate="/posts">
                  Posts
                </Phoenix.Component.link>
              </:item>
              <:item>
                <Phoenix.Component.link navigate="/comments">
                  Comments
                </Phoenix.Component.link>
              </:item>
            </.vertical_nav_nested>
          </:item>
        </.vertical_nav>
        <.vertical_nav_section id="without-header-search">
          <:title>Search</:title>
          <:item><input type="search" placeholder="Search" aria-label="Search" /></:item>
        </.vertical_nav_section>
      </:body>
      <:footer>
        <.vertical_nav id="without-header-user-menu" label="User menu">
          <:item>
            <Phoenix.Component.link navigate="/settings">
              Settings
            </Phoenix.Component.link>
          </:item>
          <:item>
            <Phoenix.Component.link navigate="/logout">
              Logout
            </Phoenix.Component.link>
          </:item>
        </.vertical_nav>
      </:footer>
    </.drawer>
  </div>
  <p style="min-inline-size: 0; padding: 1rem">Page content sits beside the drawer.</p>
</div>