Хотите заказать веб-сайт? Связаться с нами

Mantine: AppShell, Navbar, Header — компоновка

На этом уроке мы объединим всё, что изучили в предыдущих, т.е. в единое приложение. Мы разберем AppShell — главный строительный блок для каркаса любого приложения. Вы научитесь создавать полноценный макет с шапкой, навигационной панелью, основным контентом и даже сайдбаром. Это один из самых важных уроков, потому что без правильного каркаса любое приложение выглядит незавершенным.

Mantine: AppShell, Navbar, Header — компоновка

Что такое AppShell и зачем он нужен

AppShell — это компонент-контейнер, который предоставляет готовую структуру для типового макета приложения: шапка сверху, навигация слева, основной контент по центру и, при необходимости, дополнительная панель справа и подвал внизу . Все дочерние компоненты AppShell имеют position: fixed, поэтому они не скроллятся вместе со страницей.

Основные компоненты AppShell

  1. AppShell — корневой компонент, который управляет всей структурой
  2. AppShell.Header — фиксированная шапка сверху
  3. AppShell.Navbar — фиксированная навигационная панель слева
  4. AppShell.Aside — дополнительная панель справа
  5. AppShell.Footer — фиксированный подвал снизу
  6. 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>
  );
}

Разберем ключевые моменты

  1. useDisclosure — хук для управления состоянием открытия/закрытия. Возвращает opened (boolean) и toggle() (функция переключения).
  2. header={{ height: 60 }} — задает высоту шапки. Можно передать число (конвертируется в rem) или объект для адаптивности.
  3. navbar — конфигурация навигационной панели: width: 300 — ширина панели на десктопе, breakpoint: 'sm' — при ширине экрана меньше sm панель скрывается, collapsed: { mobile: !opened } — управляет видимостью на мобильных устройствах
  4. <Burger> — кнопка-гамбургер, которая появляется только на мобильных экранах (hiddenFrom="sm"). Ее нажатие переключает состояние навигации.
  5. padding="md" — отступы основного контента. Важно использовать именно этот проп, а не задавать padding вручную, потому что он участвует в расчете смещений для других компонентов.

Управление адаптивностью

Одна из главных фишек AppShell — встроенная адаптивность. Давайте разберем, как настраивать размеры для разных экранов.

Адаптивная высота шапки

Высота шапки может меняться в зависимости от ширины экрана:

<AppShell
  header={{
    height: { base: 48, sm: 60, lg: 76 },
  }}
>
  {/* ... */}
</AppShell>
  1. base — высота на самых маленьких экранах (48px)
  2. sm — высота на экранах от sm и выше (60px)
  3. 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>
  );
}

Новые элементы

  1. aside — дополнительная панель справа с собственными настройками ширины и отзывчивости
  2. footer — подвал с фиксированной высотой
  3. Два 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:

  1. AppShell — корневой компонент для построения макета
  2. AppShell.Header — фиксированная шапка
  3. AppShell.Navbar — навигационная панель с адаптивностью
  4. AppShell.Aside — дополнительная панель справа
  5. AppShell.Footer — подвал
  6. AppShell.Main — основная область с контентом
  7. Адаптивные настройки высоты, ширины и отступов через объекты с breakpoints
  8. Управление видимостью через collapsed и useDisclosure
  9. Интеграция с React Router через NavLink и Outlet

Что должно быть в вашем проекте после этого урока

  1. Создан каркас приложения с AppShell, Header и Navbar
  2. Настроено адаптивное поведение (мобильная версия с гамбургером)
  3. Добавлена навигация с использованием NavLink
  4. Настроены адаптивные размеры хотя бы для одного элемента (header или navbar)
  5. Интегрирован AppShell с React Router (или другим роутером)
  6. Использован Burger для управления состоянием мобильной навигации

В следующем уроке мы разберем работу с сетками и отзывчивой версткой — научимся создавать сложные макеты с Grid и Flex внутри основного контента.

Теги: