Appshell

Appshell is a mega layout component that aims to manage:

  • The header that appears on-top, also called the banner.
  • The main section, that appears below the header
  • The potential left-side navbar and right-side aside.

header: Appshell.Header

The header manages:

  • the burger button
  • the logo
  • the dark mode / light mode toggle (potentially)
  • the user button (potentially)
  • a set of links (potentially)

configure the header

We build a header config and provide it to AppShell as a header prop. We commonly set the height.

<AppShell /* ... */ header={{ height: 60 }} />

navbar: Appshell.Navbar

The navbar stands on the left side. It is transient on mobile devices. On desktop it is commonly always-on, but Mantine supports having a conditional collapse as well, following a distinct logic and state variable.

We build a navbar config and provide it to AppShell as a navbar prop. collapsed aims to control the display of the navbar, while breakpoint sets the breakpoint from which we go from mobile to desktop logic.

<AppShell /* ... */ navbar={{}} />
  • collapsed receives up to two boolean state variables: one for mobile and one for desktop. Most of the time, we only set mobile.
  • breakpoint controls when the collapse logic switches from mobile to desktop, aka when to use the mobile opened state versus the desktop opened state.
  • The burger button is responsible for toggling the state on and off. We hide the mobile burger button with hiddenFrom. If desktop supports collapse too, we use a distinct burger button (see below).
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure()

return (
    <AppShell
        navbar={{
            collapsed: { mobile: !opened },
            breakpoint: "sm",
        }}
    >
        <AppShell.Header>
            <Burger opened={opened} onClick={toggle} hiddenFrom="sm" />
        </AppShell.Header>
    </AppShell>
)

navbar: allow collapse on desktop

We may allow the collapse behavior on Desktop as well: we create an additional, distinct boolean state variable, and provide it to the desktop property of collapsed. We also add a dedicated desktop burger button, which commonly keeps the same appearance regardless of the collapse state (we don't show a close icon because there is no overlay). This burger button condition its display to desktop with visibleFrom.

const [mobileOpened, { toggle: toggleMobile }] = useDisclosure(false)
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true)

return (
    <AppShell
        navbar={{
            collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
            breakpoint: "sm",
        }}
    >
        <AppShell.Header>
            {/* mobile */}
            <Burger opened={mobileOpened} onClick={toggleMobile} hiddenFrom="sm" />
            {/* desktop */}
            <Burger opened={false} onClick={toggleDesktop} visibleFrom="sm" />
        </AppShell.Header>
    </AppShell>
)

navbar: other configuration

navbar={{ width: 300, /* ... */ }}
  • width controls the width in desktop mode (it is always full-screen in mobile). We provide an immediate value or an object with two or more values.

navbar: implement top and bottom sections

We may split the navbar into AppShell.Sections, and one of them may grow.

<AppShell.Navbar>
    <AppShell.Section grow> </AppShell.Section>
    <AppShell.Section> </AppShell.Section>
</AppShell.Navbar>

Appshell.Main

The container for the main panel.

We may set the panel background color. The default light theme sets a white background while the dark theme sets a dark.7 background.

Override example: we may pick a light gray background such as gray.1, so that inner containers may stand out as white. Similarly, we may change the background to dark.8 so that inner elements may standout as dark.7.

const backgroundColor = colorScheme === "dark" ? "dark.8" : "gray.1"

synopsis

the configuration objects are required if we use the matching element, except for main which may not be configured with this pattern.

<AppShell header={{}} navbar={{}} aside={{}} footer={{}}>
    <AppShell.Header />
    <AppShell.Navbar />
    <AppShell.Aside />
    <AppShell.Main />
    <AppShell.Footer />
</AppShell>
earlymorning logo

© Antoine Weber 2025 - All rights reserved

Appshell

Appshell is a mega layout component that aims to manage:

  • The header that appears on-top, also called the banner.
  • The main section, that appears below the header
  • The potential left-side navbar and right-side aside.

header: Appshell.Header

The header manages:

  • the burger button
  • the logo
  • the dark mode / light mode toggle (potentially)
  • the user button (potentially)
  • a set of links (potentially)

configure the header

We build a header config and provide it to AppShell as a header prop. We commonly set the height.

<AppShell /* ... */ header={{ height: 60 }} />

navbar: Appshell.Navbar

The navbar stands on the left side. It is transient on mobile devices. On desktop it is commonly always-on, but Mantine supports having a conditional collapse as well, following a distinct logic and state variable.

We build a navbar config and provide it to AppShell as a navbar prop. collapsed aims to control the display of the navbar, while breakpoint sets the breakpoint from which we go from mobile to desktop logic.

<AppShell /* ... */ navbar={{}} />
  • collapsed receives up to two boolean state variables: one for mobile and one for desktop. Most of the time, we only set mobile.
  • breakpoint controls when the collapse logic switches from mobile to desktop, aka when to use the mobile opened state versus the desktop opened state.
  • The burger button is responsible for toggling the state on and off. We hide the mobile burger button with hiddenFrom. If desktop supports collapse too, we use a distinct burger button (see below).
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure()

return (
    <AppShell
        navbar={{
            collapsed: { mobile: !opened },
            breakpoint: "sm",
        }}
    >
        <AppShell.Header>
            <Burger opened={opened} onClick={toggle} hiddenFrom="sm" />
        </AppShell.Header>
    </AppShell>
)

navbar: allow collapse on desktop

We may allow the collapse behavior on Desktop as well: we create an additional, distinct boolean state variable, and provide it to the desktop property of collapsed. We also add a dedicated desktop burger button, which commonly keeps the same appearance regardless of the collapse state (we don't show a close icon because there is no overlay). This burger button condition its display to desktop with visibleFrom.

const [mobileOpened, { toggle: toggleMobile }] = useDisclosure(false)
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true)

return (
    <AppShell
        navbar={{
            collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
            breakpoint: "sm",
        }}
    >
        <AppShell.Header>
            {/* mobile */}
            <Burger opened={mobileOpened} onClick={toggleMobile} hiddenFrom="sm" />
            {/* desktop */}
            <Burger opened={false} onClick={toggleDesktop} visibleFrom="sm" />
        </AppShell.Header>
    </AppShell>
)

navbar: other configuration

navbar={{ width: 300, /* ... */ }}
  • width controls the width in desktop mode (it is always full-screen in mobile). We provide an immediate value or an object with two or more values.

navbar: implement top and bottom sections

We may split the navbar into AppShell.Sections, and one of them may grow.

<AppShell.Navbar>
    <AppShell.Section grow> </AppShell.Section>
    <AppShell.Section> </AppShell.Section>
</AppShell.Navbar>

Appshell.Main

The container for the main panel.

We may set the panel background color. The default light theme sets a white background while the dark theme sets a dark.7 background.

Override example: we may pick a light gray background such as gray.1, so that inner containers may stand out as white. Similarly, we may change the background to dark.8 so that inner elements may standout as dark.7.

const backgroundColor = colorScheme === "dark" ? "dark.8" : "gray.1"

synopsis

the configuration objects are required if we use the matching element, except for main which may not be configured with this pattern.

<AppShell header={{}} navbar={{}} aside={{}} footer={{}}>
    <AppShell.Header />
    <AppShell.Navbar />
    <AppShell.Aside />
    <AppShell.Main />
    <AppShell.Footer />
</AppShell>