# 应用外壳

- 页面: https://jiguang132.com/zh/resources/mantine/docs/app-shell
- 资源: Mantine Core (https://jiguang132.com/zh/resources/mantine.md)
- 全部指南: https://jiguang132.com/zh/resources/mantine/docs.md

Mantine Core 的独立组件，请不要替换为 JGuang UI/Base UI 的同名 API。

## 安装

```bash
npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1
```

入口引入 `@mantine/core/styles.css`，并在根组件使用 `MantineProvider`；通过 `forceColorScheme` 同步深浅色主题。

## 使用与验证

在左侧选择组件，在预览中操作它的状态；使用“查看代码”检查真实源码。安装后执行类型检查和构建，再验证键盘焦点、手机布局与深浅色主题。

## 来源

https://github.com/mantinedev/mantine/tree/f0e2bc6d28b0f0b8aaefb5b859937bf77f539df7
MIT 许可证；不包括付费内容。下方提供上游英文参考内容，中文使用指南已适配；上游详细参考暂保留英文。

---


## 版本与兼容性

固定的 Mantine Core 9.7.1 要求 React 和 React DOM 满足 `^19.2.0`，并配套 `@mantine/hooks@9.7.1`。此条件来自实际 npm 包的 peerDependencies。React 18 或其他不兼容版本不能强行安装；先向项目负责人说明升级影响并确认方案，不使用 --force/--legacy-peer-deps 掩盖冲突。入口的原生 Provider 开启 `theme.respectReducedMotion`，并用 `forceColorScheme` 控制深浅色。

## 适用场景

组合应用头部、导航和主内容区域。

## 本地示例使用的原生参数

以下参数由本地、经过类型检查的 JSX 示例提取，按所属组件区分。不是全部属性清单；完整签名和继承关系见下方固定源码参考。

| 组件参数 | 说明 |
| --- | --- |
| `AppShell.header` | 应用头部布局配置。 |
| `AppShell.navbar` | 应用导航布局配置。 |
| `AppShell.padding` | 应用内容内边距配置。 |
| `AppShell.style` | 本地样式或布局对象。 |
| `AppShell.Header.p` | Mantine 内边距样式参数。 |
| `AppShell.Navbar.p` | Mantine 内边距样式参数。 |

## 交互与状态检查

当前场景：默认。切换支持的禁用、错误或只读场景后检查真实行为；无此原生状态的组件不会被强行添加统一属性。验证键盘焦点和退出方式，修改值后按原生回调签名连接业务状态。

## 业务接入边界

固定布局区域相对于预览 iframe 的可视窗口定位。真实应用需配置响应式断点与导航收起状态。

## 宿主配置

先安装固定版本 @mantine/core 和 @mantine/hooks，在入口引入 @mantine/core/styles.css，并使用 MantineProvider。示例的 theme 和 variant 是 JGuang 编写的宿主参数，不是所有原生组件都接受的统一 API；通过 forceColorScheme 同步应用主题。源码面板中的原生实现仅供阅读，使用 npm 导出，不要单独复制内部实现。此批只覆盖 Core，不包括日期、图表和表单扩展包。上游详细说明保留英文，不宣称全文中文化。


## 可运行用法

以下代码使用资源原生 API；不是把其他设计系统的同名组件替换进来。

```tsx
import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';


function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const content = <M.Text>Build something beautiful / 构建美好的界面</M.Text>;
return <M.AppShell header={{ height: 50 }} navbar={{ width: 110, breakpoint: "sm" }} padding="sm" style={{ width: "100%", minHeight: 280 }}><M.AppShell.Header p="sm">App header</M.AppShell.Header><M.AppShell.Navbar p="sm">Navigation</M.AppShell.Navbar><M.AppShell.Main>{content}</M.AppShell.Main></M.AppShell>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}

```


## 可用状态与示例

默认

示例遵循 Mantine 原生 API。支持多状态的输入组件可将示例中的 variant 改为 Disabled、Invalid 或 Read only；这些只是示例标签，不是新增的组件属性。改造时保留组件要求的数据、受控值、store 和复合子组件结构。


## Examples

This page contains documentation only. All `AppShell` components have a fixed
position; examples are included in a separate documentation section.


## Usage

`AppShell` is a layout component that can be used to create a common Header / Navbar / Footer / Aside
layout pattern. All `AppShell` components have `position: fixed` styling, so they do not scroll with
the page.

[Basic AppShell example](/app-shell?e=BasicAppShell) with header and navbar.
The navbar is hidden on mobile by default and can be toggled with the burger button.

```tsx
import { AppShell, Burger } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';

function Demo() {
  const [opened, { toggle }] = useDisclosure();

  return (
    <AppShell
      padding="md"
      header={{ height: 60 }}
      navbar={{
        width: 300,
        breakpoint: 'sm',
        collapsed: { mobile: !opened },
      }}
    >
      <AppShell.Header>
        <Burger
          opened={opened}
          onClick={toggle}
          hiddenFrom="sm"
          size="sm"
        />

        <div>Logo</div>
      </AppShell.Header>

      <AppShell.Navbar>Navbar</AppShell.Navbar>

      <AppShell.Main>Main</AppShell.Main>
    </AppShell>
  );
}
```

## AppShell components

- `AppShell` – root component that wraps all other sections and configures the overall layout.
- `AppShell.Header` – fixed header at the top, controlled by the `header` prop.
- `AppShell.Navbar` – fixed navbar on the left, controlled by the `navbar` prop.
- `AppShell.Aside` – fixed aside on the right, controlled by the `aside` prop.
- `AppShell.Footer` – fixed footer at the bottom, controlled by the `footer` prop.
- `AppShell.Main` – main content area, statically positioned and offset by the other sections.
- `AppShell.Section` – utility for grouping content inside `AppShell.Navbar` or `AppShell.Aside`, useful for scrollable areas.

## Configuration

The `AppShell` component accepts `header`, `footer`, `navbar`, and `aside` props to configure the corresponding sections.
You must set these props if you want to use the corresponding components.
For example, to use the `AppShell.Header` component, you need to set the `header` prop on the `AppShell` component.

`header` and `footer` configuration objects share the same type:

```tsx
interface Configuration {
  /** Height of the section: number, string or
   ** object with breakpoints as keys and height as values */
  height: AppShellSize | AppShellResponsiveSize;

  /** When collapsed is true, the section is hidden
   ** from the viewport and doesn't affect the AppShell.Main offset */
  collapsed?: boolean;

  /** Controls whether AppShell.Main should be offset by this section.
   ** Useful for scenarios like hiding a header based on scroll position. */
  offset?: boolean;
}
```

`navbar` and `aside` configuration objects type:

```tsx
interface Configuration {
  /** Width of the section: number, string, or
   ** object with breakpoints as keys and widths as values */
  width: AppShellSize | AppShellResponsiveSize;

  /** Breakpoint at which the section switches to mobile mode.
   ** In mobile mode, the section always has 100% width and its
   ** collapsed state is controlled by `collapsed.mobile`
   ** instead of `collapsed.desktop` */
  breakpoint: MantineBreakpoint | (string & {}) | number;

  /** Determines whether the section should be collapsed */
  collapsed?: { desktop?: boolean; mobile?: boolean };
}
```

## layout prop

`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` extends the full viewport height, while `AppShell.Header`/`AppShell.Footer` width equals the viewport width minus the width of `AppShell.Navbar` and `AppShell.Aside` ([example](/app-shell?e=AltLayout))
- `default` – `AppShell.Navbar`/`AppShell.Aside` height equals the viewport height minus `AppShell.Header`/`AppShell.Footer` height, and `AppShell.Header`/`AppShell.Footer` spans the full viewport width ([example](/app-shell?e=FullLayout))

## Resizable sections

Use the `useAppShellResize` hook together with the `resize` prop to let the user resize
`AppShell.Navbar`/`AppShell.Aside` horizontally and `AppShell.Header`/`AppShell.Footer` vertically –
with a mouse, touch, or keyboard. Only the sections passed to `useAppShellResize` get a resize
handle, the section configuration objects (`navbar={{ width, breakpoint }}` etc.) do not change:

```tsx
import { AppShell, useAppShellResize } from '@mantine/core';

function Demo() {
  const resize = useAppShellResize({
    navbar: { min: 200, max: 500 },
    header: { min: 48, max: 120 },
  });

  return (
    <AppShell
      header={{ height: 60 }}
      navbar={{ width: 300, breakpoint: 'sm' }}
      resize={resize}
    >
      <AppShell.Header>Header</AppShell.Header>
      <AppShell.Navbar>Navbar</AppShell.Navbar>
      <AppShell.Main>Main</AppShell.Main>
    </AppShell>
  );
}
```

In this example, `navbar` and `header` are passed to `useAppShellResize`, so `AppShell.Navbar` and
`AppShell.Header` render a resize handle – `AppShell.Aside` and `AppShell.Footer` keep their
configured size even if they are used elsewhere in the same `AppShell`. See the
[resizable app shell example](/app-shell?e=ResizableAppShell) for a full demo that includes a
reset button.

Note that when the `resize` prop is set (same as with `mode="static"`), the `--app-shell-*`
[CSS variables](#css-variables) are defined on the `AppShell` root element instead of `:root`, so
they can only be read from elements rendered inside the `AppShell`.

### useAppShellResize hook

The hook accepts an object with the following properties:

```tsx
interface UseAppShellResizeInput {
  /** `AppShell.Navbar` resize options, the section is resizable when set */
  navbar?: AppShellResizeSectionOptions;

  /** `AppShell.Aside` resize options, the section is resizable when set */
  aside?: AppShellResizeSectionOptions;

  /** `AppShell.Header` resize options, the section is resizable when set */
  header?: AppShellResizeSectionOptions;

  /** `AppShell.Footer` resize options, the section is resizable when set */
  footer?: AppShellResizeSectionOptions;

  /** Sizes applied to sections that have not been resized yet, usually restored from storage */
  initialSizes?: AppShellResizeSizes;

  /** Called on every pointer move during a resize */
  onResize?: (sizes: AppShellResizeSizes) => void;

  /** Called when a resize is committed */
  onResizeEnd?: (sizes: AppShellResizeSizes) => void;

  /** Called when a section is dragged across its `collapseThreshold` */
  onCollapseChange?: (section: AppShellResizeSection, collapsed: boolean) => void;
}
```

Each section option (`navbar`, `aside`, `header`, `footer`) accepts the same shape:

```tsx
interface AppShellResizeSectionOptions {
  /** Minimum size, in the same units as the section `width`/`height` configuration @default 0 */
  min?: number;

  /** Maximum size, in the same units as the section `width`/`height` configuration @default viewport size */
  max?: number;

  /** Size below which `onCollapseChange` reports the section as collapsed */
  collapseThreshold?: number;

  /** `aria-label` of the resize handle @default 'Resize navbar' | 'Resize aside' | 'Resize header' | 'Resize footer' */
  label?: string;
}
```

Note that the effective maximum is always the smaller of `max` and the current viewport size – a
`max` larger than the viewport has no effect.

Resize handles are rendered as `role="separator"` elements with an English `aria-label` by default
(`Resize navbar`, `Resize aside`, `Resize header`, `Resize footer`). Use the `label` option to
localize it or to describe the section more precisely, for example
`navbar: { min: 200, max: 500, label: 'Sidebar width' }`.

`useAppShellResize` returns a controller for every section (`navbar`, `aside`, `header`, `footer`)
with the following shape:

```tsx
interface AppShellResizeSectionController {
  /** `true` when the section was configured as resizable */
  enabled: boolean;

  /** Current size override, `undefined` when the section has not been resized */
  size: number | undefined;

  /** `true` while the section is being resized */
  active: boolean;

  /** Sets the section size, does not call `onResize`/`onResizeEnd` */
  setSize: (size: number) => void;

  /** Clears the size override, the section returns to the size defined in its configuration */
  reset: () => void;
}
```

as well as `sizes` – current size overrides of all sections, and `resetAll()` – clears size
overrides of all sections. `setSize`, `reset`, and `resetAll` never call `onResize`/`onResizeEnd`.
The returned object also carries a few fields used internally by `AppShell` to wire up the resize
handles (`options`, `activeSection`, `startResize`, `previewResize`, `endResize`,
`initCollapse`, `reportCollapse`) – you do not need to use them directly.

### Keyboard shortcuts

Every resize handle is focusable and supports the following keys. Keys for the section's other
axis (for example, `ArrowUp`/`ArrowDown` on `AppShell.Navbar`) are ignored:


Arrow key, `Home`, and `End` presses commit the size immediately, so they trigger `onResizeEnd`,
not `onResize`. Double-clicking a handle resets the section, same as calling `reset()`.

### Responsive sizes and reset

Once a section is resized, it stops following its configured `width`/`height` – including a
responsive `{ base, sm, ... }` object – until `reset()` is called. Calling `reset()` (or
double-clicking the handle) returns the section to the value currently defined in its
`width`/`height` configuration.

### Persisting sizes

Combine `useAppShellResize` with [use-local-storage](/hooks/use-local-storage) to remember sizes
between visits:

```tsx
const [sizes, setSizes] = useLocalStorage<AppShellResizeSizes>({
  key: 'app-shell-sizes',
  defaultValue: {},
});

const resize = useAppShellResize({
  navbar: { min: 200, max: 500 },
  initialSizes: sizes,
  onResizeEnd: setSizes,
});
```

`initialSizes` is applied to a section only until that section is first resized. This is what
makes the pattern above work with `useLocalStorage` – its stored value is only available after the
initial render (`getInitialValueInEffect: true` by default), and by the time it arrives the
section has not been touched yet, so it is still picked up.

`reset()` and `resetAll()` never call `onResize`/`onResizeEnd`, so calling them does not clear a
size that was already written to storage by a previous `onResizeEnd` call – clear the stored value
yourself in whatever reset handler your application uses alongside `reset()`/`resetAll()`.

### Drag-to-collapse

Set `collapseThreshold` on a section to have `onCollapseChange` report when a drag crosses that
size:

```tsx
const resize = useAppShellResize({
  navbar: { min: 200, max: 500, collapseThreshold: 120 },
  onCollapseChange: (section, collapsed) => {
    if (section === 'navbar') {
      setNavbarCollapsed(collapsed);
    }
  },
});
```

`onCollapseChange` only reports the crossing – your application still owns the `collapsed` prop of
`AppShell.Navbar`/`AppShell.Aside`/`AppShell.Header`/`AppShell.Footer`. Note that a collapsed
`AppShell.Navbar`/`AppShell.Aside` moves its resize handle off screen together with the rest of the
section, so pair drag-to-collapse with a `Burger` (or another control) rather than relying on the
handle as the way to bring the section back.

### Hiding the resize handle

Resize handles are hidden below the `AppShell.Navbar`/`AppShell.Aside` `breakpoint`, and while the
corresponding section is collapsed.

## Height configuration

The `height` property in `header` and `footer` configuration objects works as follows:

- If you pass a number, the value will be converted to [rem](/styles/rem) and used as the
  height at all viewport sizes.
- To change height based on viewport width, use an object with breakpoints as keys and height as
  values. This works the same way as [style props](/styles/style-props#responsive-styles).

Example with height as a number: `height` is converted to [rem](/styles/rem),
and `height` remains the same at all viewport sizes:

```tsx
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell header={{ height: 48 }}>
      <AppShell.Header>Header</AppShell.Header>
    </AppShell>
  );
}
```

Example with height as 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`

```tsx
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell header={{ height: { base: 48, sm: 60, lg: 76 } }}>
      <AppShell.Header>Header</AppShell.Header>
    </AppShell>
  );
}
```

## Width configuration

The `width` property in `navbar` and `aside` configuration objects works as follows:

- If you pass a number, the value will be converted to [rem](/styles/rem) and used as the
  width when the viewport is larger than `breakpoint`.
- To change width based on viewport width, use an object with breakpoints as keys and width as
  values. This works the same way as [style props](/styles/style-props#responsive-styles).
  Note that width is always 100% when the viewport is smaller than `breakpoint`.

Example with width as a number: `width` is converted to [rem](/styles/rem),
and `width` remains the same at viewport sizes larger than `breakpoint`.
The `width` is 100% when viewport width is less than `breakpoint`:

```tsx
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell navbar={{ width: 48, breakpoint: 'sm' }}>
      <AppShell.Navbar>Navbar</AppShell.Navbar>
    </AppShell>
  );
}
```

Example with width as 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`

```tsx
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell
      navbar={{ width: { sm: 200, lg: 300 }, breakpoint: 'sm' }}
    >
      <AppShell.Navbar>Navbar</AppShell.Navbar>
    </AppShell>
  );
}
```

## padding prop

The `padding` prop controls the padding of the `AppShell.Main` component. It's important to use this prop
instead of setting padding directly on `AppShell.Main` because this padding is also used to calculate offsets for
the `AppShell.Header`, `AppShell.Navbar`, `AppShell.Aside`, and `AppShell.Footer` components.

The `padding` prop works the same way as [style props](/styles/style-props#responsive-styles) and
accepts numbers, strings, and objects with breakpoints as keys and padding values. You can
reference `theme.spacing` values or use any valid CSS value.

Example with static `padding` prop:

```tsx
import { AppShell } from '@mantine/core';

function Demo() {
  return <AppShell padding="md">{/* AppShell content */}</AppShell>;
}
```

Example with responsive `padding` prop:
- `padding` is 10 when viewport width is < `theme.breakpoints.sm`
- `padding` is 15 when viewport width is >= `theme.breakpoints.sm` and < `theme.breakpoints.lg`
- `padding` is `theme.spacing.xl` when viewport width is >= `theme.breakpoints.lg`

```tsx
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell padding={{ base: 10, sm: 15, lg: 'xl' }}>
      {/* AppShell content */}
    </AppShell>
  );
}
```

## Header offset configuration

The `header` prop includes an `offset` property that allows you to control
whether the `AppShell.Main` component is offset by the header's height.
This is particularly useful when you want to collapse the `AppShell.Header`
based on scroll position. For example, you can use the [use-headroom](/hooks/use-headroom)
hook to hide the header when the user scrolls down and show it when they
scroll up ([example](/app-shell?e=Headroom)).

```tsx
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>
  );
}
```

## Collapsed navbar/aside configuration

The `navbar` and `aside` props include a `collapsed` property that accepts an object with the format `{ mobile: boolean; desktop: boolean }`.
This allows you to configure the collapsed state differently based on viewport width.

[Example](/app-shell?e=CollapseDesktop) with separate collapsed states for mobile and desktop:

```tsx
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

The `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`:

```tsx
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:

```tsx
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell>
      <AppShell.Header withBorder={false}>Header</AppShell.Header>
    </AppShell>
  );
}
```

## zIndex prop

The `zIndex` prop is available on `AppShell` and its associated sections: `AppShell.Header`, `AppShell.Navbar`, `AppShell.Aside`, and `AppShell.Footer`.
By default, all sections have a `z-index` of `100`.

To change the `z-index` of all sections, set the `zIndex` prop on the `AppShell` component:

```tsx
import { AppShell } from '@mantine/core';

// All sections will have z-index of 200
function Demo() {
  return <AppShell zIndex={200}>{/* AppShell content */}</AppShell>;
}
```

To change `z-index` of a specific section, set `zIndex` prop on that section:

```tsx
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>
  );
}
```

## Control transitions

Use the `transitionDuration` and `transitionTimingFunction` props on the `AppShell` component to control section animations:

```tsx
import { AppShell } from '@mantine/core';

function Demo() {
  return (
    <AppShell
      transitionDuration={500}
      transitionTimingFunction="ease"
    >
      {/* AppShell content */}
    </AppShell>
  );
}
```

## disabled prop

Set the `disabled` prop on the `AppShell` component to prevent all sections except `AppShell.Main` from rendering.
This is useful when you want to hide the shell on certain pages of your application.

```tsx
import { AppShell } from '@mantine/core';

function Demo() {
  return <AppShell disabled>{/* AppShell content */}</AppShell>;
}
```

## AppShell.Section component

`AppShell.Section` is used to create organized areas within `AppShell.Navbar` and `AppShell.Aside`.
Since these components are flexbox containers with `flex-direction: column`, the `AppShell.Section`
component with the `grow` prop will expand to fill the available space and can be made scrollable by setting
`component={ScrollArea}`.

In the following example:

- The first and last sections (header and footer) take only the space needed for their content
- The middle section with `grow` takes all the remaining space and becomes scrollable when content exceeds the available height

```tsx
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 that will expand to fill available space
        </AppShell.Section>
        <AppShell.Section>
          Navbar footer – always at the bottom
        </AppShell.Section>
      </AppShell.Navbar>
      <AppShell.Main>Main</AppShell.Main>
    </AppShell>
  );
}
```

## Semantic elements

Important: do not use a `<main>` element inside `AppShell.Main`, as only one `<main>` element is allowed per page.

<DataTable
  head={['Component', 'Root HTML element']}
  data={[
    [<Code>AppShell.Header</Code>, <Code>header</Code>],
    [<Code>AppShell.Footer</Code>, <Code>footer</Code>],
    [<Code>AppShell.Main</Code>, <Code>main</Code>],
    [<Code>AppShell.Navbar</Code>, <Code>nav</Code>],
    [<Code>AppShell.Aside</Code>, <Code>aside</Code>],
    [<Code>AppShell.Section</Code>, <Code>div</Code>],
  ]}
/>

## CSS variables

<DataTable
  head={['Variable', 'Description']}
  data={[
    [<Code>--app-shell-navbar-width</Code>, 'Navbar width'],
    [<Code>--app-shell-navbar-offset</Code>, 'Navbar offset'],
    [<Code>--app-shell-aside-width</Code>, 'Aside width'],
    [<Code>--app-shell-aside-offset</Code>, 'Aside offset'],
    [<Code>--app-shell-header-height</Code>, 'Header height'],
    [<Code>--app-shell-header-offset</Code>, 'Header offset'],
    [<Code>--app-shell-footer-height</Code>, 'Footer height'],
    [<Code>--app-shell-footer-offset</Code>, 'Footer offset'],
  ]}
/>

Example of using CSS variables in styles:

```scss
.main {
  min-height: calc(100dvh - var(--app-shell-header-height));
}
```

These variables are defined on `:root` by default, but on the `AppShell` root element when the
`resize` prop is set or `mode="static"` is used – in these cases they are not available to elements
rendered outside of the `AppShell`, for example, in a `Modal` or `Drawer` rendered within a `Portal`.


## 源码参数参考

以下实现签名和类型从本地固定版本源码生成。保留可选属性、原生继承类型、联合分支和 never 限制；不会将其他设计系统的 API 混入。forwardRef 实现中的 ref 属于 React 引用，不是新增业务属性。此区域是原始类型参考，不是上游说明的全文翻译。


```ts
AppShell(_props)
```



```ts
export type AppShellStylesNames =
  | 'root'
  | 'navbar'
  | 'main'
  | 'header'
  | 'footer'
  | 'aside'
  | 'section'
  | 'resizeHandle';

export type AppShellCssVariables = {
  root:
    | '--app-shell-transition-duration'
    | '--app-shell-transition-timing-function'
    | '--app-shell-resize-handle-size';
};

export interface AppShellProps
  extends BoxProps, StylesApiProps<AppShellFactory>, ElementProps<'div'> {
  /** If set, the associated components have a border @default true */
  withBorder?: boolean;

  /** Padding of the main section. Important: use `padding` prop instead of `p`. @default 0 */
  padding?: MantineSpacing | AppShellResponsiveSize;

  /** `Navbar` configuration, controls width, breakpoints and collapsed state. Required if you use `Navbar` component. */
  navbar?: AppShellNavbarConfiguration;

  /** `Aside` configuration, controls width, breakpoints and collapsed state. Required if you use `Aside` component. */
  aside?: AppShellAsideConfiguration;

  /** `Header` configuration, controls height, offset and collapsed state. Required if you use `Header` component. */
  header?: AppShellHeaderConfiguration;

  /** `Footer` configuration, controls height, offset and collapsed state. Required if you use `Footer` component. */
  footer?: AppShellFooterConfiguration;

  /** Duration of all transitions in ms @default 200 */
  transitionDuration?: number;

  /** Timing function of all transitions @default ease */
  transitionTimingFunction?: React.CSSProperties['transitionTimingFunction'];

  /** `z-index` of all associated elements @default 100 */
  zIndex?: string | number;

  /** Determines how `Navbar`/`Aside` are arranged relative to `Header`/`Footer` */
  layout?: 'default' | 'alt';

  /** If set, `Navbar`, `Aside`, `Header` and `Footer` components are hidden */
  disabled?: boolean;

  /** If set, `Header` and `Footer` components include styles to offset scrollbars. Based on `react-remove-scroll`. @default true */
  offsetScrollbars?: boolean;

  /** Determines positioning mode of all sections @default 'fixed' */
  mode?: 'fixed' | 'static';

  /** `useAppShellResize` hook instance, enables resizing of the sections configured in the hook */
  resize?: AppShellResizeController;
}

export type AppShellFactory = Factory<{
  props: AppShellProps;
  ref: HTMLDivElement;
  stylesNames: AppShellStylesNames;
  vars: AppShellCssVariables;
  staticComponents: {
    Navbar: typeof AppShellNavbar;
    Header: typeof AppShellHeader;
    Main: typeof AppShellMain;
    Aside: typeof AppShellAside;
    Footer: typeof AppShellFooter;
    Section: typeof AppShellSection;
  };
}>;

export type Mod = Record<string, any> | string;

export type BoxMod = Mod | Mod[] | BoxMod[];

export interface BoxProps extends MantineStyleProps {
  /** Class added to the root element, if applicable */
  className?: string | undefined;

  /** Inline style added to root component element, can subscribe to theme defined on MantineProvider */
  style?: MantineStyleProp;

  /** CSS variables defined on root component element */
  __vars?: CssVarsProp;

  /** `size` property passed down the HTML element */
  __size?: string;

  /** Breakpoint above which the component is hidden with `display: none` */
  hiddenFrom?: MantineBreakpoint;

  /** Breakpoint below which the component is hidden with `display: none` */
  visibleFrom?: MantineBreakpoint;

  /** Determines whether component should be hidden in light color scheme with `display: none` */
  lightHidden?: boolean;

  /** Determines whether component should be hidden in dark color scheme with `display: none` */
  darkHidden?: boolean;

  /** Element modifiers transformed into `data-` attributes, for example, `{ 'data-size': 'xl' }`, falsy values are removed */
  mod?: BoxMod;
}

export type ElementProps<
  ElementType extends React.ElementType,
  PropsToOmit extends string = never,
> = Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>;

export interface CSSProperties extends React.CSSProperties {
  [key: string]: any;
}

type MantineStyle = CSSProperties | ((theme: MantineTheme) => CSSProperties);

export type MantineStyleProp = MantineStyle | MantineStyle[] | MantineStyleProp[] | undefined;

export type CssVariable = `--${string}`;

export type CssVariables<Variable extends string = CssVariable> = Partial<Record<Variable, string>>;

export type CssVars<Variable extends string = CssVariable> =
  | CssVariables<Variable>
  | ((theme: MantineTheme) => CssVariables<Variable>)
  | CssVars<Variable>[];

export type CssVarsProp<Variable extends string = CssVariable> =
  | CssVars<Variable>
  | CssVars<Variable>[];
```


### 原生与外部类型

以下外部类型仍由 React 或资源自身依赖定义，没有手工展开为虚构属性。实际可用类型以安装版本的 TypeScript 检查为准。


```ts
Factory<{
  props: AppShellProps;
  ref: HTMLDivElement;
  stylesNames: AppShellStylesNames;
  vars: AppShellCssVariables;
  staticComponents: {
    Navbar: typeof AppShellNavbar;
    Header: typeof AppShellHeader;
    Main: typeof AppShellMain;
    Aside: typeof AppShellAside;
    Footer: typeof AppShellFooter;
    Section: typeof AppShellSection;
  };
}>
MantineStyleProps
React.CSSProperties
MantineTheme
Partial<Record<Variable, string>>
Record<Variable, string>
Variable
MantineBreakpoint
Record<string, any>
StylesApiProps<AppShellFactory>
React.ElementType
Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>
React.ComponentProps<ElementType>
ElementType
PropsToOmit
MantineSpacing
AppShellResponsiveSize
AppShellNavbarConfiguration
AppShellAsideConfiguration
AppShellHeaderConfiguration
AppShellFooterConfiguration
AppShellResizeController
HTMLDivElement
```

---

JGuang 全部资源索引: https://jiguang132.com/llms.txt
