Raft 设计系统

组件 · 布局

Panel

A column of the desktop main area with a 56px panel header and its own scrolling content; its header is also the top bar of a phone's pushed pages.

稳定也叫 NavBar, Top bar, Panel header
import { Panel } from "@botiverse/raft-ui";
本页尚未翻译
译文完成之前,这里显示英文原文。 阅读英文版

A panel is one column of the desktop main area: a panel header, then content that scrolls inside the column. Every column uses the same header, whether it holds a conversation, a thread, a side panel or a drawer's content. On a phone, PanelHeader is the top bar of a pushed page.

panel/panel

When to use

SituationUse
A column of the desktop main area, or a side panel beside it (tasks, files, a profile)Panel
A conversation: header, tabs, messages and composerConversationPanel, built on Panel
A thread beside a conversationThreadPanel
The top bar of a phone's pushed pagePanelHeader
The list of what a destination contains, next to the railSidebar
Details or settings that slide in over the pageDrawer

How the regions of a screen are arranged, and when a side panel sits beside the main area or covers it, is in Page structure and Responsive layout.

Anatomy

  • Panel: the column. edge="attached" draws a line-seam on its left edge, for a side panel next to a conversation; edge="inset" draws none.
  • PanelHeader: the 56px header with a line-seam under it. Required.
    • PanelHeaderIcon: the location tile of a place, or the avatar of a person. Optional.
    • PanelHeaderContent: holds PanelHeading and PanelMeta.
    • PanelHeading: the PanelTitle, followed by any PanelStatus (a tag such as Archived) or PanelActivity (a live status, wrapping a Status).
    • PanelMeta: one line of description under the title.
    • PanelActions: the trailing PanelAction and PanelToggleAction buttons.
  • PanelSectionHeader: the same bar for a section-level view. On a phone it sits on the frame.
  • PanelHeaderRoot: the bare 56px bar both headers are built on, for a header with its own layout.
  • PanelNotice, with PanelNoticeContent and PanelNoticeActions: a full-width strip under the header for a problem in this panel. When to use it instead of a banner is in Banner. A status pixel or an icon placed before PanelNoticeContent leads its first line (A mark that leads text).
  • PanelBody, PanelScrollViewport and PanelScrollContent: the content and its single scroll container.
  • PanelSection: a block of content with a hairline above it.
  • PanelFooter: the bottom action area, padded for the safe area.
conversation-panel/compositions/conversation-panel-header

Variants

HeaderUse for
PanelHeaderEvery desktop panel header; the white top bar of a phone's pushed page
PanelSectionHeaderA section-level view. On a phone it sits on layer-frame with foreground-on-frame text, and hides PanelHeaderIcon

A phone's pushed page has a white top bar, and its location tile stays a yellow sticker (Open questions).

States

  • A pressed PanelToggleAction, or a PanelAction with aria-pressed, is a yellow sticker: it marks the side panel that is open.
  • Other states follow States.

Behavior

  • The header stays put; only PanelScrollViewport scrolls.
  • The title and the description truncate with an ellipsis on one line each.
  • On a phone the header sticks to the top of the page.
  • When the window is shorter than 600px, the header shrinks with every other header (Spacing).

Phone top bars

The structure of a phone's top bars (the navigation row of a top-level page, Back and up to 2 icon buttons on a pushed page) is in Page structure. The top bar also follows these rules:

  • On a top-level page, put the page name in the 56px row in text-headline, with no large title and no icon tile before it (Page structure).
  • Don't put New or Search buttons in the top bar of a top-level page: search is the Search tab (Navigation).
  • Make the bell the entry to the notification center, with a pink pixel when something is new. On a phone it is only in the top bar of the first top-level page (Page structure).
  • Use the arrow-left icon for Back, not a chevron: its ink fills the icon box like other icons, so it mirrors the button at the other end without being shifted (Alignment).

Content

  • Name the place, the person or the view in PanelTitle.
  • Put a location tile (IconTile) in PanelHeaderIcon for a place, and the person's avatar for a person. Other pages have no icon: their PanelMeta says where they belong, such as the channel a thread is in.
  • Start PanelMeta with what is live, then the counts: "2 agents working · 5 members" (Working agents). Set numbers and IDs in Space Mono (Typography).
  • Put a tag on the name (Experimental, Archived, Deleted) in PanelHeading as a PanelStatus, never in PanelMeta: the description truncates, and truncation cuts off the tag's edge.

Accessibility

  • Panel renders a section. Name it with aria-label or aria-labelledby when several panels sit side by side.
  • PanelTitle renders a div. Render it as the page's heading (render={<h1 />}, or h2 inside a page that has one).
  • PanelAction wraps the Base UI Button and always renders type="button". PanelToggleAction wraps the Base UI Toggle, which sets aria-pressed.
  • Give every icon-only PanelAction and PanelToggleAction an aria-label: "Back", "Channel Details", "Close Tasks".
  • Give an icon-only PanelStatus (a muted bell) an accessible name.

Rules

  • Use this header in every panel: conversation, thread, side panel and drawer. Don't give one panel its own header or button sizes.
  • Use PanelAction for the header's icon buttons: 32px with an 18px icon and a 44px hit area on desktop (from 768px with a mouse or trackpad), 4px apart; 44px with a 22px icon, 2px apart, on a phone and on a touch screen at any width. They follow the default control height (Spacing). A 44px button next to a 17px title looks heavy on desktop; a finger needs 44px.
  • Put Back first in the header and the actions last, in PanelActions: the header pulls its first and last button out so their icon boxes, not the buttons, sit on the content margin, 20px on a desktop and on a touch screen in the desktop layout, 16px on a phone, at every button size (Alignment). Don't add margins of your own to move an edge button. Keep only PanelActions in PanelActions: the group declares their inset, so an action hidden at some width (a thread's Close below 1024px) leaves the next one on the edge. A frameless Button at icon-md or icon-lg as the header's first or last child is pulled the same way; a filled one ends its shape on the margin.
  • Give a PanelStatus its own cell on the title's line, and center it by its shape. Don't nudge it: the title's letters already sit on the line's center, so a 1px shift makes it sit high.
  • Open a side panel from the header with a PanelToggleAction: pressing it again closes the panel.
  • Give a side panel next to a conversation edge="attached", so it draws the one line between the two (Page structure).

API

Panel

Prop类型默认值
edgePanelEdge
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PanelAction

Prop类型默认值
focusableWhenDisabledWhether the button should be focusable when disabled.booleanfalse
nativeButtonWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).booleantrue
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PanelActions, PanelActivity, PanelBody, PanelFooter, PanelHeader, PanelHeaderContent, PanelHeaderIcon, PanelHeaderRoot, PanelHeading

Prop类型默认值
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PanelMeta

Prop类型默认值
size"sm" | "md""sm"
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PanelNotice

Prop类型默认值
statusThe tint: warning for something to fix (the default), destructive only for what cannot be undone.PanelNoticeStatus"warning"
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PanelNoticeActions, PanelNoticeContent, PanelScrollContent, PanelScrollViewport, PanelSection, PanelSectionHeader, PanelStatus, PanelTitle

Trailing controls (copy, a link, ×), centred on the first text line.
Prop类型默认值
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)

Also takes the attributes of its element.

PanelToggleAction

Prop类型默认值
defaultPressedWhether the toggle button is currently pressed. This is the uncontrolled counterpart of `pressed`.booleanfalse
disabledWhether the component should ignore user interaction.booleanfalse
nativeButtonWhether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).booleantrue
onPressedChangeCallback fired when the pressed state is changed.(pressed: boolean, eventDetails: BaseToggle.ChangeEventDetails) => void
pressedWhether the toggle button is currently pressed. This is the controlled counterpart of `defaultPressed`.boolean
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.ReactElement | ((props, state) => ReactElement)
valueA unique string that identifies the toggle when used inside a toggle group.string

Also takes the attributes of its element.

改动

  • 0.10.2 · FixedPanelAction and PanelToggleAction follow the same desktop condition as every other control ((width >= 48rem) and (pointer: fine)). On a touch tablet they were 32px while the rest stayed 44px; they now keep 44px with 22px icons there. Phone and desktop sizes are unchanged.
  • 0.5.40 · FixedElegant PanelHeader's icon chip: fill-muted measured 1.04:1 against the canvas-muted header (effectively invisible) and becomes fill-strong; avatar slots declare data-icon-kind="avatar" and drop the chip entirely, so a round avatar no longer sits on a square. Brutal's black-bordered chip is unchanged.
  • 0.5.36 · ChangedPanel alignment: the elegant PanelHeader puts its icon box on the 20px line and the title on the 68px line (36px to 20px at md+, gap 8 to 12); MessageItem rows in both themes carry the 8px inset (7px padding + 1px border, 6px + 2px in Brutal) that lands the avatar on 20 and the text on 68 next to the 12px the app shell keeps. Brutal also drops the row's mx-3, taking the mobile avatar inset from 32 to 20. The thread panel uses the chat panel's figures.
  • 0.5.0 · Breaking ChangesElegant PanelHeaderIcon now owns its container treatment. It renders as a 36px rounded muted surface instead of a bare auto-sized slot. Remove redundant consumer wrappers and update layouts that relied on the previous intrinsic size.
  • 0.4.0 · Breaking ChangesPanelHeaderIcon no longer sizes its icon. The slot dropped the [&_svg] sizing (brutal 18px / elegant 14px stroke 2.5); consumers must now size icons themselves, e.g. with a size-* class or the size attribute. ([0295c2e](https://github.com/botiverse/rui/commit/0295c2e))
  • 0.3.0 · Breaking ChangesRenamed PanelHeaderFrame to PanelHeaderRoot and updated the corresponding type and data-slot from panel-header-frame to panel-header-root. Panel header parts remain available from the package root and are now owned by the shared Panel vocabulary.
  • 0.3.0 · AddedAdded AppShellPanelSlot and AppShellOverlaySlot, overlay-aware main slots, attached/inset Panel edges, and the shared PanelActivity header part for composable multi-panel layouts.
  • 0.2.0 · Breaking ChangesGeneralized panel chrome: replace PanelHeader with PanelHeaderFrame, and replace ConversationPanelActions, ConversationPanelHeader*, ConversationPanelHeading, ConversationPanelMeta, ConversationPanelSectionHeader, ConversationPanelStatus, and ConversationPanelTitle with their Panel* counterparts. Update selectors targeting the renamed data-slot values.