Acronis UIKit
Components

App Shell Chat

A three-column application scaffold — navigation rail, page content, and a resizable live-chat panel.

Usage

import {
  AppShellChat,
  AppShellChatSidebar,
  AppShellChatContent,
  AppShellChatContentHeader,
  AppShellChatContentBody,
  AppShellChatChat,
  AppShellChatChatHeader,
  AppShellChatChatBody,
  useAppShellChatInitialLayout,
  getAppShellChatInitialLayout,
} from '@acronis-platform/ui-react';

AppShellChat is the full-page scaffold for a screen that pairs page content with a persistent chat/assistant panel — a slot-based layout of three columns: a sidebar rail, the Content column, and the Chat panel. Drop SidebarPrimary (and optionally SidebarSecondary) into the sidebar slot; the scaffold only paints surfaces and the column dividers, and the slotted components bring their own styling. The Chat slot is optional — omit AppShellChatChat and the same scaffold serves an ordinary two-column screen.

Sizing. Content is flex-1 and can shrink to 0; Chat carries an explicit pixel width. Because Chat is never sized as a percentage, expanding, collapsing, or resizing a sidebar only reflows Content — Chat keeps its width. That invariant is why this is not built on Resizable, which sizes panels as a percentage of their group.

Resizing. Chat is resize-only — there is no separate collapse or full-width toggle. Drag the handle on its inline-start border (the shared boundary with Content), double-click that handle or press Home to reset, and use ArrowLeft/ArrowRight to nudge it in 16px steps. The floor is 48px, where AppShellChatChatHeader switches to an icon-only rail and AppShellChatChatBody hides; the ceiling is measured from the row's actual free space, so dragging far enough shrinks Content to 0 and Chat fills the row.

Initial layout. Chat's own default width is plain responsive CSS — 512px at 1680px and up, 448px from 1280–1679px, and the 48px rail below that — live on every browser resize until the user resizes it themselves. The sidebars are the opposite: their initial expanded state is resolved once at mount by useAppShellChatInitialLayout() and wired into each sidebar's defaultExpanded. Wiring is the consumer's job because AppShellChatSidebar is a plain slot, not a fixed sidebar pairing. getAppShellChatInitialLayout(width) is the same mapping as a pure function, for tests and for SSR-supplied widths.

Mapped to the App Shell Chat Figma.

Examples

The preview above controls the chat width so it stays inside the page. A real screen leaves it uncontrolled and wires only the sidebars' initial state:

function Screen() {
  const initialLayout = useAppShellChatInitialLayout();

  return (
    <AppShellChat className="h-screen">
      <AppShellChatSidebar>
        <SidebarPrimary defaultExpanded={initialLayout.primaryExpanded}>
          {/* … */}
        </SidebarPrimary>
        <SidebarSecondary defaultExpanded={initialLayout.secondaryExpanded}>
          {/* … */}
        </SidebarSecondary>
      </AppShellChatSidebar>
      <AppShellChatContent>
        <AppShellChatContentHeader>Page header</AppShellChatContentHeader>
        <AppShellChatContentBody>{children}</AppShellChatContentBody>
      </AppShellChatContent>
      <AppShellChatChat>
        <AppShellChatChatHeader label="Acronis AI" />
        <AppShellChatChatBody>{/* chat */}</AppShellChatChatBody>
      </AppShellChatChat>
    </AppShellChat>
  );
}

SidebarSecondary is optional — omit it and the rail is SidebarPrimary alone.

Persist the width, add header actions, and relabel the resize handle:

function AssistantPanel() {
  const [chatWidth, setChatWidth] = useState(loadStoredWidth);

  return (
    <AppShellChatChat
      width={chatWidth}
      onWidthChange={setChatWidth}
      resizeAriaLabel="Resize the assistant panel"
      resizeTooltip={null} // omit the drag/reset hint
    >
      <AppShellChatChatHeader
        label="Acronis AI"
        actions={
          <ButtonIcon aria-label="Close assistant">
            <TimesIcon />
          </ButtonIcon>
        }
      />
      <AppShellChatChatBody>{/* chat */}</AppShellChatChatBody>
    </AppShellChatChat>
  );
}

Parts

ExportElementPurpose
AppShellChatdivThe full-height row.
AppShellChatSidebarasideNav rail slot (SidebarPrimary [+ Secondary]).
AppShellChatContentdivThe page column; absorbs every width change, can shrink to 0.
AppShellChatContentHeaderdivPage header row, with a bottom divider.
AppShellChatContentBodydivScrolling page content.
AppShellChatChatasideThe resizable chat panel; renders its own resize handle.
AppShellChatChatHeaderdivChat title + actions, or the icon-only rail at the floor width.
AppShellChatChatBodydivScrolling chat content; hidden at the floor width.

Every part accepts the native attributes of the element it renders, plus className (use it to size the root, pad the bodies, etc.). The resize handle is rendered automatically inside AppShellChatChat and is not a public part.

API Reference

AppShellChatChat

Prop

Type

AppShellChatChatHeader

Prop

Type

AppShellChatInitialLayout

Returned by useAppShellChatInitialLayout() and getAppShellChatInitialLayout(viewportWidth).

Prop

Type

AppShellChat and the remaining structural parts add no props of their own — they accept the standard attributes of the element listed in Parts.

Edit on GitHub

On this page