组件 · 导航
Sidebar
The desktop column next to the rail that lists what the selected destination contains, with rows that mark where you are, what is unread and what mentions you.
import { Sidebar } from "@botiverse/raft-ui";The sidebar is the desktop column between the rail and the main area. It lists what the destination selected on the AppRail contains: channels, agents and people, for example. Its header names the destination, and its rows show where you are, what is unread and what mentions you.
When to use
| Situation | Use |
|---|---|
| The contents of a desktop destination | Sidebar |
| The same list on a phone | Sidebar rows, on the page itself; below md they are 44px |
| The destinations themselves | AppRail |
| Activity and notifications | InboxItem |
Which destinations have a sidebar, and what each one lists, is the product's choice (Raft Chat). A destination without a sidebar puts its content next to the rail (Page structure).
Anatomy
SidebarRoot: the column, onlayer-sidebar, with aline-seamalong its right edge.SidebarHeader: the 56px header, with aSidebarHeaderTitleand, on its right, the working summary when someone is working.SidebarBodyandSidebarContent: the scrolling list.SidebarSection: a group of rows.SidebarSectionHeader: holds aSidebarSectionDisclosure(the button that collapses the group, withSidebarSectionChevron,SidebarSectionTitleandSidebarSectionCount) and, inSidebarSectionTrailingorSidebarSectionControls,SidebarSectionControlbuttons such as New.SidebarSectionAttentionis the group's pink pixel.SidebarList: the rows.SidebarSectionEmptyreplaces them when the group is empty.
SidebarMenu, withSidebarMenuIcon,SidebarMenuTitle,SidebarMenuAsideandSidebarMenuCount: a single destination in a section header, such as Saved.SidebarGroupLabel: a plain group heading that doesn't collapse.SidebarItem: one row.- First, a
SidebarItemChannelIcon, aSidebarItemIconor a 19px Avatar. SidebarItemContent: theSidebarItemTitle(the name) and an optionalSidebarItemSubtitle(a description).SidebarItemAside: what follows:SidebarItemMeta,SidebarItemMetaIcon,SidebarItemStatus, the unreadSidebarItemCount(withSidebarItemThreadCountandSidebarItemCountSeparator), or the mention markerSidebarItemIndicator.
- First, a
States
| State | Look |
|---|---|
active | A yellow sticker: you are here. It doesn't change on hover; a press lays sticker-medium |
tone="unread" | A bold name and a pink SidebarItemCount. When someone mentions the person, a yellow SidebarItemIndicator replaces the count |
tone="muted" | A bell-off SidebarItemMetaIcon, the name in foreground-muted, and the unread number as quiet text in SidebarItemMeta |
tone="away" | Offline, or not joined: the name in foreground-hint |
| Menu open | data-popup-open (a context menu, or press and hold on a phone): fill-subtle, the same subtle tier as the hover, so the row the menu acts on stays marked; an active row stays the sticker (Hover and press) |
interactive={false} | A display-only row, such as this computer, whose action is a button inside it: a div that doesn't react to hover or press |
Behavior
- The sidebar is 240px wide and can be dragged between 200px and 400px; it keeps one width on every page that has it (Spacing).
- A name stays on one line and ends with an ellipsis. A description after it gives up its room first; the name truncates only once the description is gone.
- A row whose content is 2 lines (a computer's name and whether it runs agents) uses
wrapwithSidebarItemContent stacked: it grows from 36px, its text stays 8px from the row's edges, and its icon lines up with the first line. The name still stays on one line. - A collapsed group shows how many rows it holds in
SidebarSectionCount. - While an agent works, what it is doing replaces its runtime (Working agents), in
text-footnoteandforeground-muted, and takes at most 58% of the row.
Content
- Title the header with the destination's name.
- Mark a channel with a bare
#icon, a private channel withlock, and agents and people with their 19px avatar. - Write an agent's runtime in Space Mono after its name.
Accessibility
SidebarRootrenders adiv. Render it as anasideor anavand name it after the destination:aria-label="Chat".SidebarItemrenders the Base UI Button. For a row that navigates, render a link (render={<a href="…" />}) and setaria-current="page"on theactiverow:activeonly changes how it looks.- Give the unread count a name that says what it counts ("2 unread"), and give an icon-only
SidebarItemMetaIcona name ("Muted"). SidebarSectionDisclosureis a Base UI Collapsible trigger, which setsaria-expanded.- On a display-only row, focus lands only on the controls inside it.
Rules
- Draw a row the same way in every group: original, pinned or custom. A group never changes a row (no wrapping, no hidden description in one group), because the same conversation would look like two different things.
- Don't use
wrapto let a name run onto more lines, including in a pinned group. Use it only for a row whose content is 2 lines. - Make every row 36px high, in
text-subhead, on a desktop. Belowmdthe row grows on its own to at least 44px intext-bodyat 600: there it is a phone list of places (Home, Members, the Settings list), which a finger has to hit. Don't add phone sizes at the callsite. The Settings list sat at 36px on phones because the size lived in one product class that only Home's rows were given. - Don't put the server switcher in the sidebar header. It is in the web top bar, or at the top of the rail when there is no top bar.
- Don't use
SidebarLiveActivityfor a live bar at the bottom of the sidebar. Working agents appear in the header's working summary and in their own rows instead (Working agents).
API
SidebarBody, SidebarLiveActivity, SidebarContent, SidebarGroupLabel, SidebarHeader, SidebarHeaderTitle, SidebarItemAside, SidebarItemCount, SidebarItemCountSeparator, SidebarItemChannelIcon
| Prop | 类型 | 默认值 |
|---|---|---|
| Allows 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.
SidebarItem
| Prop | 类型 | 默认值 |
|---|---|---|
| boolean | ||
| `false` renders a display-only `div`: no button, no type, nothing to press. Its own controls (an action button) stay the targets. | boolean | true |
| Something waits for you (a 700 name), the place is muted (an ink-2 name), or it is away: offline or not joined (an ink-3 name). | RowTone | "default" |
| For a row whose content is two lines (a name and a second line): the row grows from its fixed height and its content aligns to the first line. The name itself stays on one line and truncates, in every group (Sidebar's rules); never use this to let a long name wrap. | boolean | false |
| Allows 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.
SidebarItemIcon, SidebarItemIndicator
| Prop | 类型 | 默认值 |
|---|---|---|
| Allows 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.
SidebarItemContent
| Prop | 类型 | 默认值 |
|---|---|---|
| boolean | false | |
| Allows 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.
SidebarItemMeta, SidebarItemMetaIcon, SidebarItemStatus, SidebarItemSubtitle
| Prop | 类型 | 默认值 |
|---|---|---|
| Allows 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.
SidebarItemThreadCount
| Prop | 类型 | 默认值 |
|---|---|---|
| Visually hidden words read after the number, so screen readers hear what the count is (the icon is decorative). Pass localized copy. | string | "threads with new replies" |
| Allows 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.
SidebarItemTitle
| Prop | 类型 | 默认值 |
|---|---|---|
| Allows 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.
SidebarList
| Prop | 类型 | 默认值 |
|---|---|---|
| Allows the browser's built-in page search to find and expand the panel contents. | boolean | false |
| Whether to keep the element in the DOM while the panel is hidden. This prop is ignored when `hiddenUntilFound` is used. | boolean | false |
| Allows 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.
SidebarMenu, SidebarMenuAside, SidebarMenuCount, SidebarMenuIcon, SidebarMenuTitle, SidebarRoot
| Prop | 类型 | 默认值 |
|---|---|---|
| Allows 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.
SidebarControl
| Prop | 类型 | 默认值 |
|---|---|---|
| boolean | ||
| string | ||
| `md` (32px) and `icon-md` for rows, cards, banners, toolbars and panel headers; `lg` and `icon-lg` (the control height) for dialog footers, forms and beside a field; `xl` for a full-width call to action. The size follows the place: see Button › Size by place. | "md" | "lg" | "xl" | "icon-md" | "icon-lg" | DeprecatedButtonSize | |
| "primary" | "accent" | "warning" | "danger" | "default" | "outline" | "information" | "muted" | "success" | "danger-secondary" | "danger-outline" | "ghost" | "on-frame" | ||
| Allows 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.
SidebarSection
| Prop | 类型 | 默认值 |
|---|---|---|
| Whether the collapsible panel is initially open. | boolean | true |
| Whether the component should ignore user interaction. | boolean | false |
| Event handler called when the panel is opened or closed. | (open: boolean, eventDetails: CollapsibleRootChangeEventDetails) => void | |
| Whether the collapsible panel is currently open. | boolean | |
| Allows 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.
SidebarSectionEmpty
| Prop | 类型 | 默认值 |
|---|---|---|
| Allows the browser's built-in page search to find and expand the panel contents. | boolean | false |
| Whether to keep the element in the DOM while the panel is hidden. This prop is ignored when `hiddenUntilFound` is used. | boolean | false |
| Allows 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.
SidebarSectionControl
| Prop | 类型 | 默认值 |
|---|---|---|
| boolean | false | |
| string | "Loading" | |
| `md` (32px) and `icon-md` for rows, cards, banners, toolbars and panel headers; `lg` and `icon-lg` (the control height) for dialog footers, forms and beside a field; `xl` for a full-width call to action. The size follows the place: see Button › Size by place. | "md" | "lg" | "xl" | "icon-md" | "icon-lg" | DeprecatedButtonSize | "icon-md" |
| "primary" | "accent" | "warning" | "danger" | "default" | "outline" | "information" | "muted" | "success" | "danger-secondary" | "danger-outline" | "ghost" | "on-frame" | "ghost" | |
| Allows 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.
SidebarSectionControls, SidebarSectionDisclosure, SidebarSectionChevron, SidebarSectionCount, SidebarSectionHeader
| Prop | 类型 | 默认值 |
|---|---|---|
| Allows 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.
SidebarSectionAttention
| Prop | 类型 | 默认值 |
|---|---|---|
| A status light (online, busy, error, offline, external): a fixed meaning that needs its word nearby, or an aria-label. It takes the place of `variant`'s colour. | "online" | "busy" | "error" | "offline" | "external" | |
| "xs" | "sm" | "md" | "lg" | "md" | |
| "primary" | "accent" | "warning" | "danger" | "default" | "information" | "muted" | "success" | ||
| Allows 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.
SidebarSectionTitle, SidebarSectionTrailing
| Prop | 类型 | 默认值 |
|---|---|---|
| Allows 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.
相关组件
改动
- 0.8.1 · FixedBelow
md, aSidebarItemrow is at least 44px high in the 16px title type, so a phone sidebar row can be tapped without help from the app. - 0.6.1 · Added
SidebarItemtakestone(RowTone, shared with ListRow) andinteractive={false}for a display-only row whose own buttons are the targets. - 0.6.0 · Breaking ChangesProps that no longer change anything are removed:
Badgeuppercase;Checkboxsize,variant,color;Statuspulse,attention(status never animates);Switch/SwitchThumbsize;SidebarItemvariant;SidebarItemCount/SidebarItemIndicatorvariantandappearance(the count is always the pink sticker, the indicator the yellow @);NotificationCenterActionButtonvariant;DrawerContentwidth(one-go forms use the wideDialog);AppRailItemIndicatorattention;AppRailItemAttentionchildren;Stepssize,track,renderIndicator,renderTraveler;FilePreviewBadgetype,color. Remove them at call sites. - 0.5.64 · Changed
SidebarItemThreadCountdraws the package'sThreadIcon(was lucideMessageSquare), at 12px with a 1.75 stroke; badge height is unchanged. - 0.5.60 · Added
SidebarItemThreadCount(thread icon + number of followed threads with new replies, with a visually hidden, localizablelabelfor screen readers) andSidebarItemCountSeparator(the dot between counts), so a channel row'sSidebarItemCountcan read5 · [thread] 1. Both also work as quiet text insideSidebarItemMetafor muted channels.SidebarItemCountstays as tight as a plain number when it holds the thread icon. - 0.5.35 · Changed
SidebarSection's attention badge no longer hides on its own while a section menu is open. The section's own open state and header hover still hide it; to also hide it while a menu is open, the header must mirror the menu's open state onto itself asdata-popup-open(the docs composition shows the wiring). - 0.5.0 · Breaking ChangesBrutal
SidebarItemactive styling is neutral by default. Active items now use a white surface instead of pink. Passvariant="accent"to preserve the previous pink treatment, orvariant="primary"for yellow.