import { Layout } from '@/layout'; import { MDX_DATA } from '@/mdx';
export default Layout(MDX_DATA.AppShell);
This page includes only documentation. Since all associated AppShell
components have fixed
position, it is not possible to include demos on this page.
AppShell
is a layout component. It can be used to implement a common Header – Navbar – Footer – Aside
layout pattern. All AppShell
components have position: fixed
style – they are not scrolled with
the page.
Basic AppShell example with header and navbar. Navbar is hidden on mobile by default and toggled with the burger button.
import { AppShell, Burger } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
function Demo() {
const [opened, { toggle }] = useDisclosure();
return (
<AppShell
header={{ height: 60 }}
navbar={{
width: 300,
breakpoint: 'sm',
collapsed: { mobile: !opened },
}}
padding="md"
>
<AppShell.Header>
<Burger
opened={opened}
onClick={toggle}
hiddenFrom="sm"
size="sm"
/>
<div>Logo</div>
</AppShell.Header>
<AppShell.Navbar p="md">Navbar</AppShell.Navbar>
<AppShell.Main>Main</AppShell.Main>
</AppShell>
);
}
AppShell
– root component, it is required to wrap all other components, used to configure layout propertiesAppShell.Header
– header section rendered at the top of the page, has fixed position, its height and collapsed state are controlled by the AppShellheader
propAppShell.Navbar
– navbar section rendered at the left side of the page, has fixed position, its width and collapsed state are controlled by the AppShellnavbar
propAppShell.Aside
– aside section rendered at the right side of the page, has fixed position, its width and collapsed state are controlled by the AppShellaside
propAppShell.Footer
– footer section rendered at the bottom of the page, has fixed position, its height and collapsed state are controlled by the AppShellfooter
propAppShell.Main
– main section rendered at the center of the page, has static position, all other sections are offset by its paddingAppShell.Section
– utility component that can be used to render group of content insideAppShell.Navbar
andAppShell.Aside
, can be used to create areas with custom scrollbars
AppShell
component accepts, header
, footer
, navbar
and aside
props to configure
corresponding sections. It is required to set these props if you want to use corresponding
components. For example, if you want to use AppShell.Header
component, you need to set header
prop on the AppShell
component.
header
and footer
configuration objects are the same and have the following properties:
interface Configuration {
/** Height of the section: number, string or
** object with breakpoints as keys and height as value */
height: AppShellSize | AppShellResponsiveSize;
/** If section is collapsed,
** it is hidden from the viewport and is not offset in AppShell.Main */
collapsed?: boolean;
/** Determines whether the section should be offset by the AppShell.Main.
** For example, it is useful if you want to
** hide header based on the scroll position. */
offset?: boolean;
}
navbar
and aside
configuration objects are the same as well and have the following properties:
interface Configuration {
/** Width of the section: number, string or
** object with breakpoints as keys and width as value */
width: AppShellSize | AppShellResponsiveSize;
/** Breakpoint at which section should switch to mobile mode
** In mobile mode the section always has 100% width and its
** collapsed state is controlled by the `collapsed.mobile`
** instead of `collapsed.desktop` */
breakpoint: MantineBreakpoint | (string & {}) | number;
/** Determines whether the section should be collapsed */
collapsed?: { desktop?: boolean; mobile?: boolean };
}
layout
prop controls how AppShell.Header
/AppShell.Footer
and AppShell.Navbar
/AppShell.Aside
are positioned relative to each other. It accepts alt
and default
values:
alt
–AppShell.Navbar
/AppShell.Aside
height is equal to viewport height,AppShell.Header
/AppShell.Footer
width is equal to viewport width -AppShell.Navbar
andAppShell.Aside
width (example)default
–AppShell.Navbar
/AppShell.Aside
height is equal to viewport height -AppShell.Header
/AppShell.Footer
height,AppShell.Header
/AppShell.Footer
width is equal to viewport width (example)
height
property in header
and footer
configuration objects works the following way:
- If you pass a number, the value will be converted to rem and used as height at all viewport sizes.
- To change height based on viewport width, use object with breakpoints as keys and height as values. It works the same way as style props.
Examples:
import { AppShell } from '@mantine/core';
// Height is a number, it will be converted to rem
// and used as height at all viewport sizes
function Demo() {
return (
<AppShell header={{ height: 48 }}>
<AppShell.Header>Header</AppShell.Header>
</AppShell>
);
}
import { AppShell } from '@mantine/core';
// Height is an object with breakpoints:
// - height is 48 when viewport width is < theme.breakpoints.sm
// - height is 60 when viewport width is >= theme.breakpoints.sm and < theme.breakpoints.lg
// - height is 76 when viewport width is >= theme.breakpoints.lg
function Demo() {
return (
<AppShell header={{ height: { base: 48, sm: 60, lg: 76 } }}>
<AppShell.Header>Header</AppShell.Header>
</AppShell>
);
}
width
property in navbar
and aside
configuration objects works the following way:
- If you pass a number, the value will be converted to rem and used as
width when the viewport is larger than
breakpoint
. - To change width based on viewport width, use object with breakpoints as keys and width as
values. It works the same way as style props.
Note that width is always 100% when the viewport is smaller than
breakpoint
.
Examples:
import { AppShell } from '@mantine/core';
// Width is a number, it will be converted to rem
// and used as width when viewport is larger than theme.breakpoints.sm
function Demo() {
return (
<AppShell navbar={{ width: 48, breakpoint: 'sm' }}>
<AppShell.Navbar>Navbar</AppShell.Navbar>
</AppShell>
);
}
import { AppShell } from '@mantine/core';
// Width is an object with breakpoints:
// - width is 100% when viewport width is < theme.breakpoints.sm
// - width is 200 when viewport width is >= theme.breakpoints.sm and < theme.breakpoints.lg
// - width is 300 when viewport width is >= theme.breakpoints.lg
function Demo() {
return (
<AppShell
navbar={{ width: { sm: 200, lg: 300 }, breakpoint: 'sm' }}
>
<AppShell.Navbar>Navbar</AppShell.Navbar>
</AppShell>
);
}
padding
prop controls the padding of the AppShell.Main
component. It is important to use it
instead of setting padding on the AppShell.Main
directly because padding of the AppShell.Main
is
also used to offset AppShell.Header
, AppShell.Navbar
, AppShell.Aside
and AppShell.Footer
components.
padding
prop works the same way as style props and
accepts numbers, strings and objects with breakpoints as keys and padding as values. You can
reference theme.spacing
values or use any valid CSS values.
import { AppShell } from '@mantine/core';
// Padding is always theme.spacing.md
function Demo() {
return <AppShell padding="md">{/* AppShell content */}</AppShell>;
}
import { AppShell } from '@mantine/core';
// Padding is:
// - 10 when viewport width is < theme.breakpoints.sm
// - 15 when viewport width is >= theme.breakpoints.sm and < theme.breakpoints.lg
// - theme.spacing.xl when viewport width is >= theme.breakpoints.lg
function Demo() {
return (
<AppShell padding={{ base: 10, sm: 15, lg: 'xl' }}>
{/* AppShell content */}
</AppShell>
);
}
header
prop has offset
property which allows removing AppShell.Header
offset from AppShell.Main
component.
It is useful when you want to collapse AppShell.Header
based on the scroll position. For example, you can use
use-headroom hook to collapse header when user scrolls down and expand it when user scrolls up (example).
import { AppShell, rem } from '@mantine/core';
import { useHeadroom } from '@mantine/hooks';
function Demo() {
const pinned = useHeadroom({ fixedAt: 120 });
return (
<AppShell
header={{ height: 60, collapsed: !pinned, offset: false }}
padding="md"
>
<AppShell.Header>Header</AppShell.Header>
<AppShell.Main
pt={`calc(${rem(60)} + var(--mantine-spacing-md))`}
>
{/* Content */}
</AppShell.Main>
</AppShell>
);
}
navbar
and aside
props have collapsed
property. The property accepts an object
{ mobile: boolean; desktop: boolean }
which allows to configure collapsed state
depending on the viewport width.
Example with separate collapsed state for mobile and desktop:
import { AppShell, Button } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
export function CollapseDesktop() {
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure();
const [desktopOpened, { toggle: toggleDesktop }] =
useDisclosure(true);
return (
<AppShell
padding="md"
header={{ height: 60 }}
navbar={{
width: 300,
breakpoint: 'sm',
collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
}}
>
<AppShell.Header>Header</AppShell.Header>
<AppShell.Navbar>Navbar</AppShell.Navbar>
<AppShell.Main>
<Button onClick={toggleDesktop} visibleFrom="sm">
Toggle navbar
</Button>
<Button onClick={toggleMobile} hiddenFrom="sm">
Toggle navbar
</Button>
</AppShell.Main>
</AppShell>
);
}
withBorder
prop is available on AppShell
and associated sections: AppShell.Header
, AppShell.Navbar
, AppShell.Aside
and AppShell.Footer
.
By default, withBorder
prop is true
– all components have a border on the side that is adjacent to the AppShell.Main
component.
For example, AppShell.Header
is located at the top of the page – it has a border on the bottom side,
AppShell.Navbar
is located on the left side of the page – it has a border on the right side.
To remove the border from all components, set withBorder={false}
on the AppShell
:
import { AppShell } from '@mantine/core';
// None of the components will have a border
function Demo() {
return (
<AppShell withBorder={false}>{/* AppShell content */}</AppShell>
);
}
To remove the border from a specific component, set withBorder={false}
on that component:
import { AppShell } from '@mantine/core';
// AppShell.Header does not have a border
// AppShell.Navbar and AppShell.Aside have a border
function Demo() {
return (
<AppShell>
<AppShell.Header withBorder={false}>Header</AppShell.Header>
<AppShell.Navbar>Navbar</AppShell.Navbar>
<AppShell.Aside>Aside</AppShell.Aside>
</AppShell>
);
}
zIndex
prop is available on AppShell
and associated sections: AppShell.Header
, AppShell.Navbar
, AppShell.Aside
and AppShell.Footer
.
By default, all sections z-index
is 200
.
To change z-index
of all sections, set zIndex
prop on the AppShell
:
import { AppShell } from '@mantine/core';
// All sections will have z-index of 100
function Demo() {
return <AppShell zIndex={100}>{/* AppShell content */}</AppShell>;
}
To change z-index
of a specific section, set zIndex
prop on that section:
import { AppShell } from '@mantine/core';
// AppShell.Header has z-index of 100
// AppShell.Navbar and AppShell.Aside have z-index of 300
function Demo() {
return (
<AppShell>
<AppShell.Header zIndex={100}>Header</AppShell.Header>
<AppShell.Navbar zIndex={300}>Navbar</AppShell.Navbar>
<AppShell.Aside zIndex={300}>Aside</AppShell.Aside>
</AppShell>
);
}
Set transitionDuration
and transitionTimingFunction
props on the AppShell
to control transitions:
import { AppShell } from '@mantine/core';
function Demo() {
return (
<AppShell
transitionDuration={500}
transitionTimingFunction="ease"
>
{/* AppShell content */}
</AppShell>
);
}
Set disabled
prop on the AppShell
to prevent all sections except AppShell.Main
from rendering.
It is useful when you want to hide the shell on some pages of your application.
import { AppShell } from '@mantine/core';
function Demo() {
return <AppShell disabled>{/* AppShell content */}</AppShell>;
}
AppShell.Section
component can be used to create scrollable areas inside AppShell.Navbar
and AppShell.Aside
.
Root elements of AppShell.Navbar
and AppShell.Aside
are flexbox containers with flex-direction: column
,
AppShell.Section
with grow
attribute will take all available space and will be scrollable if component={ScrollArea}
is set.
In the following example:
- First and last sections (header and footer) will take as much space as they need to render
children
- Second section will take all available space and will be scrollable if content height exceeds available space
import { AppShell, ScrollArea } from '@mantine/core';
function Demo() {
return (
<AppShell navbar={{ width: 300, breakpoint: 0 }}>
<AppShell.Navbar>
<AppShell.Section>Navbar header</AppShell.Section>
<AppShell.Section grow component={ScrollArea}>
Navbar main section, it will
</AppShell.Section>
<AppShell.Section>
Navbar footer – always at the bottom
</AppShell.Section>
</AppShell.Navbar>
<AppShell.Main>Main</AppShell.Main>
</AppShell>
);
}
AppShell.Header
root element isheader
AppShell.Navbar
root element isnav
AppShell.Aside
root element isaside
AppShell.Footer
root element isfooter
AppShell.Main
root element ismain
– !important: do not usemain
element insideAppShell.Main
component