Skip to content

Releases

v0.83.0

Choose a tag to compare

@github-actions github-actions released this 10 Nov 09:04
4759f01

Added

  • placement="top" on DialogContent, on a desktop and a tablet (and on DialogSheetContent there): the dialog stays centered across, its top edge at var(--dialog-top, 8vh), and it is never taller than the window less that top and 16px, so it never runs past the window's bottom. Its width still comes from size. The content carries data-placement="top". To anchor the card to something, the app measures it and sets --dialog-top in the content's style; raft-ui measures nothing. Below 768px it does nothing.
    • Why: search opens from the top bar's field, and its panel's top edge belongs on the field, which a centered dialog can't do (slock drew it on DialogSurface with its own positioning, #triage:#278).
    • Affects: nothing until a dialog passes placement="top": "center", the default, renders the same DOM and classes as before.
    • Docs: https://raft-design.botiverse.build/components/dialog/#at-the-top
  • On a phone every centered dialog moves up while the on-screen keyboard is open, whatever its placement: its top edge goes where the phone's top bar ends (--header-height below the top of what is visible, under the status bar), it ends at least 16px above the keyboard, and it goes back to the middle when the keyboard closes. While lifted the content carries data-soft-keyboard. A phone sheet doesn't move; it keeps its own keyboard box.
    • Why: a centered dialog covered by the keyboard is always wrong, its field or its buttons out of sight, so this is platform behavior and no app opts in (stdrc, 2026-10-21: centered unless the keyboard is open). slock did it with its own narrow="top"; that maps to the default now.
    • Affects: every centered DialogContent below 768px, only while a text field in it has focus and the visible area is over 100px shorter than the window; at rest nothing changes. A DialogSheetContent's keyboard box now reads the keyboard through the same check, once a frame: a focused checkbox, radio or button no longer counts as typing. An app that lifted its dialogs itself (slock's narrow="top") can drop that code.
    • Docs: https://raft-design.botiverse.build/components/dialog/#the-keyboard
  • SelectionToolbar (from @botiverse/raft-ui/wip): the floating toolbar for selected items (messages, tasks), in the BatchBar style. SelectionToolbarDock floats it 12px above the bottom (plus the safe area) and 20px from the sides; SelectionToolbarCount (with the number in SelectionToolbarCountValue, Space Mono), SelectionToolbarHint, SelectionToolbarActions with SelectionToolbarAction (secondary, menu, moreItem), SelectionToolbarMore with SelectionToolbarMoreItems in its menu, SelectionToolbarItem for another control such as a select-all checkbox, and SelectionToolbarClose. A floating panel's frame (line-seam ring, shadow-float) as tall as a head: 44px with md buttons 4px apart with a mouse, 56px with 44px bar buttons side by side showing their icons alone by touch. It is a Base UI Toolbar (one Tab stop, arrow keys inside) and never wraps: when its row doesn't fit the width it floats in, measured, the hint, the secondary actions, the labels (the first action's last) and then the other actions give way, the last first; the count and × stay.
    • Why: the toolbar for selected items is one bar shared by message multi-select and task bulk actions, in Noel's BatchBar style: md ghost buttons with a 14px icon and a label, no primary (stdrc, 2026-11-10, #wg-task-v2); by touch it aligns with the head, so a phone fits the tasks' Status, Assignee and Nudge at 360px (Noel, 2026-11-10).
    • Affects: nothing yet. The stable MessageMultiSelectToolbar and MessageMultiSelectToolbarActions keep their earlier bar until SelectionToolbar leaves wip; move to it from @botiverse/raft-ui/wip when you are ready.
    • Docs: https://raft-design.botiverse.build/components/selection-toolbar/, https://raft-design.botiverse.build/components/#toolbar-for-selected-items
  • FitToolbar (from @botiverse/raft-ui/wip): a Base UI Toolbar whose items give way in named steps as the region it sits in narrows: label (to an icon), more (into More), collapse (a group to one button) and wrap (a group to a line of its own, with wrap; groups with the same wrapLine share one, and a wrapped group gets back what its items gave before it wrapped). Items declare their steps and order with useFitItem, or are a FitToolbarButton; a FitToolbarGroup overflow="scroll" scrolls sideways instead, its data-active items kept in view; groups are FitToolbarGroup (firstLine, wrapOrder, wrapLine, collapsed, collapseOrder); More takes useFitMore and lists FitToolbarMoreItems. It measures its own region's width, never the window's, again when its content changes on its own, and writes each step as data-fit-<step>. A SegmentedControl inside it follows its label step; its own iconsOnlyBelow is off there.
    • Why: one measured engine for every toolbar that has to give way (responsive.md "measure the content rather than guess a width"), used by SelectionToolbar now and meant for the list toolbars of #proj-raft-ui:#225, instead of a breakpoint guess or a hook per app. Its step names and API stay in wip until sindresorhus confirms them for those toolbars.
    • Docs: https://raft-design.botiverse.build/components/fit-toolbar/

Changed

  • DialogSheetContent, DialogCommit and DialogSheetBack are stable: import them, and their props types, from @botiverse/raft-ui. @botiverse/raft-ui/wip no longer exports them.
    • Why: slock is moving its own dialogs, its phone sheets among them, onto raft-ui (#triage:#278), and a product builds on the stable entry.
    • Affects: an import from @botiverse/raft-ui/wip fails; import from @botiverse/raft-ui instead. No app imported them from /wip (slock draws its sheets itself today), and the docs' examples have moved.
    • Docs: https://raft-design.botiverse.build/components/dialog/#making-a-dialog-a-sheet

Fixed

  • A label/value list puts its labels above when a chip or a long word of a wrapping value can't fit beside its label: DescriptionList direction="horizontal" and MessageActionCard's properties now also stack when one chip of a value that wraps either way (a row of chips wider than the list) is wider than the value column but no wider than the list, and likewise when a long word in such a value (an ID, a commit SHA, a URL) is: beside the label the chip was cut and the word ran past the value column. A word set to overflow-wrap: anywhere breaks where it must, and doesn't decide. There is no new prop.
    • Why: the one-line rule let a row of chips wider than the list stay beside its labels, where one long chip was cut off with no way to read it (mobile #4507, the Computer page's Detected Runtimes chip).
    • Affects: lists whose value wraps either way and holds a chip or a long word wider than the value column now stack instead of staying beside their labels (slock's Computer page among them). Such a word used to run past the value column in DescriptionList and break mid-word in MessageActionCard properties; it now reads whole on its own line. Every other list lays out as before; the extra measurement runs only for values wider than the list.
    • Docs: https://raft-design.botiverse.build/components/description-list/#labels-go-above-only-when-a-value-doesnt-fit
  • The server tab's popover keeps one whole server row and opens on the current server: MobileNavServerPopoverList is never shorter than one two-line row. Where the footer actions and the pages would leave it less inside 60% of the screen, MobileNavServerPopoverContent grows past 60% as far as that row needs; where the screen is too short even for that, the whole popover scrolls, the footer and the pages with it, in a ScrollArea. On open the list scrolls, with no animation, to the row with aria-current="true", and focus goes to that row (a touch still focuses the popover itself), so focus no longer scrolls the list back to the top.
    • Why: with 5 pages in the grid, a 360dp phone squeezed the list until the current server was half hidden, and the list always opened at the top (Lagoon, mobile #4500; Jasper's review of raft-design #1117).
    • Affects: every MobileNavServerPopoverContent. A popover that fit before is unchanged except that it opens scrolled to the current server; one whose list was squeezed below a row is now taller than 60%, or scrolls as a whole. Opening from a mouse or keyboard focuses the current server's row instead of the first row; pass initialFocus to choose otherwise. The popover's parts now sit in a ScrollArea (data-slot="mobile-nav-server-popover-scroll") inside the popup, so a selector for a direct child of mobile-nav-server-popover-content no longer matches them. Mark the current server's row with aria-current="true" for the scroll and the focus to find it.
    • Docs: https://raft-design.botiverse.build/components/mobile-nav/#the-server-tab
  • A settings row's switch centers on its text, not on the SaveStatus line under it: in a ListRow variant="plain" whose ListRowBody ends with a SaveStatus, both ends (the switch, value, chevron, checkbox, radio or button, and a leading icon, avatar or tile) center on the title and description. The row moves the line's reserved space (4px and one footnote line) into its bottom padding, so its height is unchanged and nothing moves when "Saved" or a one-line error appears. There is no new prop.
    • Why: the ends centered on the whole body, the empty reserved line included, so the switch sat visibly below the text (slock's Administration › Hide #all channel; Jasper and Kirby, 2026-11-09, #proj-raft-ui:#220).
    • Affects: in such rows the ends move up by half the reserved line (11px). A row without a SaveStatus is unchanged. An error that wraps still grows the row, and the ends move down by half of each extra line. Beside a title alone on a phone, the 30p...
Read more

v0.82.0

Choose a tag to compare

@github-actions github-actions released this 09 Nov 16:05
0c1c765

Changed

  • OtterIndicator uses Ottie's approved four poses: relaxed side-lying, quiet typing, a puzzled head tilt with a question mark, and one celebratory hop. The SVG props and ref remain supported. It pauses outside the viewport and in hidden documents; reduced motion shows a still. The HTML art layer sizes from the SVG box so Safari/WebKit scales it correctly at 40px and larger.
    • Why: the previous unrelated otter drawing and sleeping wait pose did not match Ottie or the recent-activity card (Artea's approved B study).
    • Affects: consumers of OtterIndicator, including Raft's recent-activity card. Artwork loads as separate transparent WebP files only for a displayed status; there is no frame timer or per-frame React update.
    • Docs: https://raft-design.botiverse.build/components/steps/#ottie-illustration

Breaking

  • ComposerDropOverlayPrompt takes its text as children, which is required: the icon cluster stays, and the text under it is what you pass. It no longer falls back to the built-in "Drop files to attach", and children no longer replace the icons.
    • Why: the component library carried product copy in English that no app could translate (Remy's helper-text sweep, #proj-workspace:#250).
    • Affects: <ComposerDropOverlayPrompt /> no longer type-checks; pass the text, e.g. <ComposerDropOverlayPrompt>{t("dropToAttach")}</ComposerDropOverlayPrompt>. A caller that passed children for a label without icons uses ComposerDropOverlayLabel instead.
    • Docs: https://raft-design.botiverse.build/components/composer/

Added

  • Data parts beside the explanation parts: three additive parts, so data no longer has to sit in a slot meant for a sentence that explains. Nothing existing changes: no prop, part or style is renamed or restyled.
    • ListRowSubtitle: data about a row's subject under its title (an agent's description, a channel's topic, an app's byline), in the title's ink at 400 and text-footnote. It follows the row's tone and disabled state with the title. ListRowDescription stays the place for a setting's consequence.
    • ChoiceList items take meta: lines of data people compare across rows (a quota, free disk, a count, a status), in text-footnote in foreground-muted as the description is, after the description lines. A row still draws at most two lines in all, the description's first; a meta line has a description line's height, so moving a line from one to the other doesn't move the rows. Radios and checkboxes are described by the description lines, then the meta lines.
    • MessageActionCardHeaderMeta: the time on a resolved card, in Space Mono at the hint tier: a line of its own under the title, or the end of the MessageActionCardHeaderDescription line it is placed in ("Approved by Martin · 10:51").
    • Why: grey text is to mean one of two things, a sentence written to explain or a component's own notes on its data (times, counts, IDs), and data people read as the content uses the body ink. Apps had put data in the explanation parts (ListRowDescription, a ChoiceList item's description, MessageActionCardHeaderDescription) because there was nowhere else for it; these parts give it a place before those parts are kept for explanations (Kirby, Remy's helper-text plan).
    • Affects: nothing until an app uses them. Data moved into ListRowSubtitle gets darker and a size smaller than in ListRowDescription; data moved into a ChoiceList item's meta looks as it did in description; a time moved into MessageActionCardHeaderMeta is set in Space Mono at the hint tier.
    • Docs: https://raft-design.botiverse.build/components/list-row/#data-and-explanation, https://raft-design.botiverse.build/components/choice-list/#content, https://raft-design.botiverse.build/components/message-action-card/#anatomy

Fixed

  • A Resizable seam's handle no longer covers the scrollbar beside it: the 12px handle (24px under a coarse pointer) lies over the start of the panel after the boundary instead of straddling it; its hover and focus line stays on the seam.

    • Why: a panel's scrollbar runs along its end edge, the seam's other side, and the centered handle covered its last 6px, where the thumb is, so dragging the thumb resized the panel instead (Raft app's Activity list, #proj-raft-ui:21bae128).
    • Affects: the handle now takes the pointer over the first 12px of the next panel (24px by touch) instead of 6px on each side. Nothing else moves.
    • Docs: https://raft-design.botiverse.build/components/resizable/#behavior
  • ScrollArea measures in the frame after mounting, not while React commits: where a ResizeObserver watches the sizes, the first read of the container's clientHeight and scrollHeight waits for the next animation frame, as every later one already did. Without a ResizeObserver it still measures at once.

    • Why: the read in the commit forced a layout of the whole page each time an area mounted. Entering a server in the Raft app mounts the sidebar, the message list and the panels at once, and those reads took about 120ms of layout (InNOut's measurement, #proj-frontend:#40).
    • Affects: the frame runs before the paint that first shows the area, so nothing on screen changes. Until it runs, an overflowing area has no thumb length and no overflow classes, and onEdgeChange is first called in it: code that reads them in a layout effect right after mounting finds them unset, and can call actionsRef.measure for a measure at once.
    • Docs: https://raft-design.botiverse.build/components/scroll-area/

Full Changelog: v0.81.0...v0.82.0

v0.81.0

Choose a tag to compare

@github-actions github-actions released this 09 Nov 09:44
90f6f96

Fixed

  • ScrollArea's scrollbars paint over everything inside the area: the gutters layer is at the highest z-index, and the area's root is a stacking context of its own (isolation: isolate), so a sticky heading or any other positioned content inside the area, whatever its z-index, no longer covers the thumb, with sticky and absolute gutters alike, and the scrollbars still never paint over anything outside the area.
    • Why: in the Raft app's activity list each day's sticky heading (an opaque background at z-15) painted over the thumb as it slid by, cutting it into pieces, while the gutters were at z-1 (Artea, #proj-raft-ui:21bae128). Starting the scrollbar below the stuck heading (railInset) fixed only the heading at the top, not the ones scrolling past.
    • Affects: content inside a ScrollArea can no longer cover anything outside it, whatever its z-index: a popup, a menu or a dragged copy rendered in place inside an area stacks with the area. Render those through a portal (raft-ui's overlays do, and now DragLift by default, below). The scrollbars' strip at the edge now takes the pointer over positioned content there too, as it already did over the rest. How the scrollbars look is unchanged.
    • Docs: https://raft-design.botiverse.build/components/scroll-area/
  • DragLift renders the copy in document.body by default: the lifted copy goes through a portal to the body unless container names another element, or null keeps it in place; the portal keeps the theme scope it was rendered in. TaskDragOverlay follows, as SortableTabsList and SortableComposerAttachments already did.
    • Why: in place inside a ScrollArea, now a stacking context, the copy couldn't rise above anything outside the area. On the Raft app's Tasks board a dragged card was cut off by the left rail and covered by the top bar (TaskDragOverlay with no container).
    • Affects: a DragLift or TaskDragOverlay without container now renders its copy in the body: CSS that styles the copy through an ancestor of the item (.board [data-slot=drag-lift]) no longer reaches it, and neither do CSS variables set on that ancestor; style the copy through its own children. The writing direction (dir) is carried over, below. Pass container={null} for the old in-place copy. How the copy looks is unchanged.
    • Docs: https://raft-design.botiverse.build/components/drag/#anatomy
  • In a right-to-left layout the dragged copy keeps its direction: DragLift's portal carries the item's computed writing direction (dir) to the body, as it carries the theme scope.
    • Why: in the body, the copy took its direction from <html>, so an item dragged out of a right-to-left container came out left-to-right (Jasper's review of #1094).
    • Affects: a copy of an item in a dir="rtl" container now lays out right-to-left. Nothing else around the item reaches the copy (font, colour, a container's custom properties); the docs now say so.
    • Docs: https://raft-design.botiverse.build/components/drag/#anatomy
  • ChoiceList's row actions keep clear of the scrollbar: in a list that scrolls (search on, or fill), a row's action sits 12px from the end instead of 4px, and rows with an action keep their text 52px from the end instead of 44px.
    • Why: the scrollbar's 16px strip at the end of a ScrollArea now paints over and takes the pointer from everything in the area; the last 8px of each 32px action lay under it, so a click there paged the list instead.
    • Affects: in a scrolling ChoiceList, each action moves 8px toward the start, and a long name or description cuts off 8px sooner. A list that doesn't scroll is unchanged.
    • Docs: https://raft-design.botiverse.build/components/choice-list/#behavior

Full Changelog: v0.80.0...v0.81.0

v0.80.0

Choose a tag to compare

@github-actions github-actions released this 09 Nov 06:08
9cf4cdd

Changed

  • A panel head is one line from 768px by touch too: PanelHeaderContent puts the PanelMeta after the title on its line from 768px at any pointer, where it used to do so only with a mouse; a phone still puts it under the title.
    • Why: a touch tablet stacked the title and its count while a laptop showed them on one line, so the same page looked different on the two, and the Raft app had started overriding the layout page by page (xxchan, Kirby, #proj-workspace:dc3c9fc9).
    • Affects: on a touch screen 768px or wider, every panel head (Tasks, Artifacts, a thread, a profile, a channel) shows its subtitle on the title's line, and the subtitle truncates first. Head heights don't change (56px by touch). An app that stacked them itself can drop its override.
    • Docs: https://raft-design.botiverse.build/components/panel/#anatomy

Fixed

  • A gallery row of three images sits three across: MessageImageGalleryRow with three images (count: 3) lays them out three across at every width, on the shorter rows already sized for three, where it used to put two over one.
    • Why: six images showed as rows of 2, 1, 2, 1 and read as an F (xxchan, #triage:c3c22ffb).
    • Affects: three, six and nine images in a message now show three to a row; each image is narrower (about 117px instead of 178px in a 360px gallery), so a wide screenshot is cropped more in the thumbnail. Opening an image still shows all of it.
    • Docs: https://raft-design.botiverse.build/components/message-attachment/#rules

Full Changelog: v0.79.0...v0.80.0

v0.79.0

Choose a tag to compare

@github-actions github-actions released this 09 Nov 05:13
05682de

Changed

  • A sidebar row out of view isn't laid out or painted: SidebarItem sets content-visibility: auto, with one line (1lh) as its content height until it has been laid out (the last laid-out height after that, for a row that wraps) and a 2px overflow-clip-margin.
    • Why: a server with hundreds of channels relaid every row whenever the window's width changed, about 115ms per relayout at 300 channels (InNOut, #proj-frontend:57f32c96). On a 300-row sidebar, a width sweep's layout time drops from 95–122ms to 29–33ms (70 width changes, 3 runs each).
    • Affects: nothing visible. The selected row's outer sticker edge, which reaches 1.5px past the row, still paints. A browser without overflow-clip-margin keeps laying every row out. Something an app draws past a row's box by more than 2px gets clipped.
    • Docs: https://raft-design.botiverse.build/components/sidebar/#behavior

Full Changelog: v0.78.0...v0.79.0

v0.78.0

Choose a tag to compare

@github-actions github-actions released this 08 Nov 21:31
bbdbf19

Changed

  • raft-ui/prefer-scroll-area also reads class lists kept in a const and a className property: a native-scrolling class in a const of the same file is reported when the const is used as a class there (const log = "max-h-64 overflow-auto", then className={log} or cn(log)), wherever in the file it is declared; and so is one in a className, class or *ClassName property, such as a recipe slot's option (content({ className: "overflow-y-auto" })). The escape comment works on them as before. (#1078)
    • Why: apps keep many class lists in consts; Stamp's port of the rule found four native scrollers this way that the rule missed (Kirby, #proj-raft-ui:#209).
    • Affects: upgrading can report scrollers the rule didn't see before; fix them, or mark an allowed exception. The Raft app gets one, the onboarding form panel (ONBOARDING_CREATE_FORM_PANEL_CLASS); its desktop app none. A string in a const that is never used as a class is still not reported.
    • Docs: https://raft-design.botiverse.build/about/use-raft-ui/#lint-rules

Full Changelog: v0.77.1...v0.78.0

v0.77.1

Choose a tag to compare

@github-actions github-actions released this 08 Nov 19:42
6ebc191

Fixed

  • The lint plugin's recommended config keeps the app's own Oxlint plugins: recommended.json sets "plugins": []. (#1076)
    • Why: an extended config without plugins counts as Oxlint's default plugins, so extending it turned unicorn back on in an app that lists its plugins without it (36 new warnings in slock, Kirby, #proj-raft-ui:#209). Same on Oxlint 1.85, 1.87 and 1.91.
    • Affects: an app that extends recommended.json keeps exactly the plugins it lists; an app that lists none keeps Oxlint's defaults, as before. The ESLint config is unchanged.
    • Docs: https://raft-design.botiverse.build/about/use-raft-ui/#lint-rules

Full Changelog: v0.77.0...v0.77.1

v0.77.0

Choose a tag to compare

@github-actions github-actions released this 08 Nov 18:57
8dc1a27

Changed

  • Select, Combobox and ComboboxSelect lists scroll in a ScrollArea: each list is a useScrollAreaContainer container with absolute gutters, inside a frame (data-slot="select-list-frame", combobox-list-frame) that holds the overlay scrollbar. The list is never a Tab stop: focus stays in the input or on the options. (#1074)
    • Why: they were the last native-scrolling exception for Base UI lists; on Windows they drew a classic scrollbar with arrows that took width from the options (Artea's runtimes list, #proj-raft-ui:20a421bd).
    • Affects: the scrollbar is the thin overlay thumb on every platform. SelectList / ComboboxList render a frame <div> around the list element; ref, className, style and the other props still go to the list. CSS or tests that expected the list to be the popup's direct child, or waited on document.getAnimations() to finish (the thumb runs on a scroll timeline), need updating.
    • Docs: https://raft-design.botiverse.build/components/scroll-area/

Full Changelog: v0.76.1...v0.77.0

v0.76.1

Choose a tag to compare

@github-actions github-actions released this 08 Nov 15:50
af1ca0b

Fixed

  • Select and Combobox lists never scroll sideways: a Select list reaches into the popup's 4px inset and pads it back, so a SelectSeparator meets the popup's edge and stays inside the list, and Select and Combobox lists set overflow-x-hidden. (#1070)
    • Why: the separator reached 4px past each side of the list, which is the scroller, so the list scrolled sideways by 8px, and a classic scrollbar (Windows) drew a horizontal bar under the runtimes list (Artea, #proj-raft-ui:20a421bd). The list also clipped the line 4px short of the popup's edge.
    • Affects: every Select with a separator, such as the runtime picker's Show installed only row: no sideways scroll, and the line now runs to the popup's border. Options keep their inset. A list action keeps its highlight after it adds items above it, as before.
    • Docs: https://raft-design.botiverse.build/components/scroll-area/

Full Changelog: v0.76.0...v0.76.1

v0.76.0

Choose a tag to compare

@github-actions github-actions released this 08 Nov 15:43
64c1ad0

Changed

  • VirtualList writes no --virtual-list-width: the list no longer writes its width as a CSS variable on its scroller, and refreshListWidth() on its imperative API does nothing (deprecated; it will be removed). (#1068)
    • Why: the variable inherits, so a write on the scroller restyled every row under it, on every frame of a window resize, and nothing read it (InNOut's trace of a window drag in the app, #proj-frontend:57f32c96).
    • Affects: CSS that read var(--virtual-list-width) gets nothing; read the width with the list's onResize or a ResizeObserver. Neither raft-ui nor the Raft app read it.
    • Docs: https://raft-design.botiverse.build/components/virtual-list/

Fixed

  • Resizing a window no longer restyles everything inside a ScrollArea: the sizes ScrollArea measures are no longer written on the root. With sticky gutters, the viewport's height (--r-scroll-area-viewport-height) and the container's padding (--r-scroll-area-padding-top, -left and -right) go on the gutters layer, and with fade the viewport's height and width (--r-scroll-area-viewport-width) on the content its mask is on; with absolute gutters, which read none of them, nothing is written. They are registered not to inherit (@property). A message timeline (useScrollAreaContainer on a VirtualList) restyled every message on every frame of a window drag. (#1068)
    • Why: in the app, dragging the window's edge took 61-73ms a frame, 75-85% of it restyling, because the viewport's size changed on the root of each column's message list (InNOut, #proj-frontend:57f32c96).
    • Affects: dragging the window's edge in the Raft app (a channel with a thread open, 1600 to 900 to 1600px wide): style recalculation 2.7s to 1.5s and the median step 52 to 27ms with this release, 0.3s and 17ms together with the app's own fix. CSS that read those variables inside an area now sees their initial values (100% and 0px); they were internal, and neither raft-ui nor the Raft app read them. How the scrollbars and fade look is unchanged.
    • Docs: https://raft-design.botiverse.build/components/scroll-area/

Full Changelog: v0.75.0...v0.76.0