Mantine: AppShell, Navbar, Header — компоновка
На этом уроке мы объединим всё, что изучили в предыдущих, т.е. в единое приложение. Мы разберем AppShell — главный строительный блок для каркаса любого приложения. Вы научитесь создавать полноценный макет с шапкой, навигационной панелью, основным контентом и даже сайдбаром. Это один из самых важных уроков, потому что без правильного каркаса любое приложение выглядит незавершенным.
Что такое AppShell и зачем он нужен
AppShell имеют position: fixed, поэтому они не скроллятся вместе со страницей.Основные компоненты AppShell
AppShell— корневой компонент, который управляет всей структуройAppShell.Header— фиксированная шапка сверхуAppShell.Navbar— фиксированная навигационная панель слеваAppShell.Aside— дополнительная панель справаAppShell.Footer— фиксированный подвал снизуAppShell.Main— основная область с контентом, которая адаптируется под отступы других элементов
Важное примечание: в Mantine 9 компоненты AppShell пишутся через точечную нотацию: AppShell.Header, AppShell.Navbar, AppShell.Main. Это важно, потому что в более старых версиях использовался другой синтаксис.
Базовый пример: шапка и навигация
Давайте создадим простейший макет с шапкой и навигационной панелью:
import { AppShell, Burger, Group, Title, Text } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
function BasicAppShell() {
const [opened, { toggle }] = useDisclosure();
return (
<AppShell
header={{ height: 60 }}
navbar={{
width: 300,
breakpoint: 'sm',
collapsed: { mobile: !opened },
}}
padding="md"
>
<AppShell.Header>
<Group h="100%" px="md">
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
<Title order={3}>Мое приложение</Title>
</Group>
</AppShell.Header>
<AppShell.Navbar p="md">
<Text fw={700}>Навигация</Text>
<Text size="sm" c="dimmed" mt="sm">
Пункт 1
</Text>
<Text size="sm" c="dimmed">
Пункт 2
</Text>
<Text size="sm" c="dimmed">
Пункт 3
</Text>
</AppShell.Navbar>
<AppShell.Main>
<Text>Основной контент страницы</Text>
</AppShell.Main>
</AppShell>
);
}
Разберем ключевые моменты
useDisclosure— хук для управления состоянием открытия/закрытия. Возвращаетopened(boolean) иtoggle()(функция переключения).header={{ height: 60 }}— задает высоту шапки. Можно передать число (конвертируется вrem) или объект для адаптивности.navbar— конфигурация навигационной панели:width: 300— ширина панели на десктопе,breakpoint: 'sm'— при ширине экрана меньшеsmпанель скрывается,collapsed: { mobile: !opened }— управляет видимостью на мобильных устройствах<Burger>— кнопка-гамбургер, которая появляется только на мобильных экранах (hiddenFrom="sm"). Ее нажатие переключает состояние навигации.padding="md"— отступы основного контента. Важно использовать именно этот проп, а не задаватьpaddingвручную, потому что он участвует в расчете смещений для других компонентов.
Управление адаптивностью
Одна из главных фишек AppShell — встроенная адаптивность. Давайте разберем, как настраивать размеры для разных экранов.
Адаптивная высота шапки
Высота шапки может меняться в зависимости от ширины экрана:
<AppShell
header={{
height: { base: 48, sm: 60, lg: 76 },
}}
>
{/* ... */}
</AppShell>
base— высота на самых маленьких экранах (48px)sm— высота на экранах отsmи выше (60px)lg— высота на экранах отlgи выше (76px)
Адаптивная ширина навигации
Аналогично можно настроить ширину навигационной панели:
<AppShell
navbar={{
width: { base: 200, sm: 250, lg: 300 },
breakpoint: 'sm',
}}
>
{/* ... */}
</AppShell>
На экранах меньше breakpoint ширина панели будет 100% от ширины экрана.
Адаптивные отступы контента
Отступы основного контента тоже можно сделать адаптивными:
<AppShell
padding={{ base: 10, sm: 15, lg: 'xl' }}
>
{/* ... */}
</AppShell>
Расширенный пример: шапка, навигация и дополнительная панель
Создадим более сложный макет со всеми элементами:
import { AppShell, Burger, Group, Title, Text, Button, Box } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
function FullAppShell() {
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure();
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true);
return (
<AppShell
header={{ height: { base: 50, md: 70 } }}
navbar={{
width: { base: 200, md: 280, lg: 320 },
breakpoint: 'sm',
collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
}}
aside={{
width: { base: 180, md: 220 },
breakpoint: 'md',
collapsed: { mobile: true, desktop: false },
}}
footer={{ height: { base: 40, md: 50 } }}
padding="md"
>
<AppShell.Header>
<Group h="100%" px="md" justify="space-between">
<Group>
<Burger
opened={mobileOpened}
onClick={toggleMobile}
hiddenFrom="sm"
size="sm"
/>
<Burger
opened={desktopOpened}
onClick={toggleDesktop}
visibleFrom="sm"
size="sm"
/>
<Title order={3}>Мое приложение</Title>
</Group>
<Button variant="subtle" size="sm">
Войти
</Button>
</Group>
</AppShell.Header>
<AppShell.Navbar p="md">
<Text fw={700} mb="md">
Основная навигация
</Text>
<Box py="xs">
<Text size="sm">📊 Дашборд</Text>
</Box>
<Box py="xs">
<Text size="sm">👥 Пользователи</Text>
</Box>
<Box py="xs">
<Text size="sm">⚙️ Настройки</Text>
</Box>
<Box py="xs">
<Text size="sm">📁 Проекты</Text>
</Box>
</AppShell.Navbar>
<AppShell.Aside p="md">
<Text fw={700} mb="md" size="sm">
Дополнительно
</Text>
<Text size="xs" c="dimmed">
Статус: Онлайн
</Text>
<Text size="xs" c="dimmed" mt="xs">
Уведомлений: 3
</Text>
</AppShell.Aside>
<AppShell.Main>
<Text size="lg" fw={500}>
Добро пожаловать в приложение!
</Text>
<Text size="sm" c="dimmed" mt="sm">
Здесь будет основной контент страницы. Шапка, навигация, дополнительная панель и подвал
адаптируются под размер экрана.
</Text>
</AppShell.Main>
<AppShell.Footer p="xs">
<Text size="xs" ta="center" c="dimmed">
© 2026 Мое приложение. Все права защищены.
</Text>
</AppShell.Footer>
</AppShell>
);
}
Новые элементы
aside— дополнительная панель справа с собственными настройками ширины и отзывчивостиfooter— подвал с фиксированной высотой- Два
Burger— один для мобильного меню, другой для десктопного
Собери свой код. Запусти сайт!
От наброска на салфетке до первого работающего лендинга. Наш онлайн-курс «Веб-верстка с нуля и до профессионала» — это интенсивный трек, где ты не будешь зубрить теорию, а с первого дня начнешь превращать идеи в чистый HTML и CSS.
Собери свой первый проект под руководством практикующих разработчиков.
Важные пропсы и настройки
layout — положение компонентов
Проп layout управляет тем, как компоненты позиционируются относительно друг друга:
// По умолчанию: навигация занимает высоту экрана минус шапка
<AppShell layout="default">
{/* ... */}
</AppShell>
// Альтернативный вариант: навигация на всю высоту, шапка не перекрывается навигацией
<AppShell layout="alt">
{/* ... */}
</AppShell>
withBorder — рамки между секциями
По умолчанию все секции имеют рамку со стороны, прилегающей к основному контенту:
// Убираем рамки у всех компонентов
<AppShell withBorder={false}>
{/* ... */}
</AppShell>
// Или у конкретного компонента
<AppShell.Header withBorder={false}>
{/* ... */}
</AppShell.Header>
zIndex — управление слоями
Все секции по умолчанию имеют z-index: 100:
// Меняем z-index для всех секций
<AppShell zIndex={200}>
{/* ... */}
</AppShell>
Полный пример с маршрутизацией (React Router)
В реальном приложении AppShell обычно оборачивает маршруты. Вот как это выглядит с React Router:
// AppShellLayout.tsx
import { AppShell, Burger, Group, Title, NavLink } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { Outlet, NavLink as RouterNavLink } from 'react-router-dom';
import { IconHome, IconUsers, IconSettings } from '@tabler/icons-react';
export function AppShellLayout() {
const [opened, { toggle }] = useDisclosure();
return (
<AppShell
header={{ height: 60 }}
navbar={{
width: 280,
breakpoint: 'sm',
collapsed: { mobile: !opened },
}}
padding="md"
>
<AppShell.Header>
<Group h="100%" px="md">
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
<Title order={3}>Мое приложение</Title>
</Group>
</AppShell.Header>
<AppShell.Navbar p="md">
<NavLink
label="Главная"
leftSection={<IconHome size={18} />}
component={RouterNavLink}
to="/"
/>
<NavLink
label="Пользователи"
leftSection={<IconUsers size={18} />}
component={RouterNavLink}
to="/users"
/>
<NavLink
label="Настройки"
leftSection={<IconSettings size={18} />}
component={RouterNavLink}
to="/settings"
/>
</AppShell.Navbar>
<AppShell.Main>
<Outlet />
</AppShell.Main>
</AppShell>
);
}
// App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { AppShellLayout } from './AppShellLayout';
import { HomePage } from './pages/HomePage';
import { UsersPage } from './pages/UsersPage';
import { SettingsPage } from './pages/SettingsPage';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<AppShellLayout />}>
<Route index element={<HomePage />} />
<Route path="users" element={<UsersPage />} />
<Route path="settings" element={<SettingsPage />} />
</Route>
</Routes>
</BrowserRouter>
);
}
Итоги
Сегодня вы научились создавать полноценный каркас приложения с помощью AppShell:
AppShell— корневой компонент для построения макетаAppShell.Header— фиксированная шапкаAppShell.Navbar— навигационная панель с адаптивностьюAppShell.Aside— дополнительная панель справаAppShell.Footer— подвалAppShell.Main— основная область с контентом- Адаптивные настройки высоты, ширины и отступов через объекты с
breakpoints - Управление видимостью через
collapsedиuseDisclosure - Интеграция с React Router через
NavLinkиOutlet
Что должно быть в вашем проекте после этого урока
- Создан каркас приложения с
AppShell,HeaderиNavbar - Настроено адаптивное поведение (мобильная версия с гамбургером)
- Добавлена навигация с использованием
NavLink - Настроены адаптивные размеры хотя бы для одного элемента (
headerилиnavbar) - Интегрирован
AppShellс React Router (или другим роутером) - Использован
Burgerдля управления состоянием мобильной навигации
В следующем уроке мы разберем работу с сетками и отзывчивой версткой — научимся создавать сложные макеты с Grid и Flex внутри основного контента.