react-resizable-panels: React components for resizable layouts: panel groups, grids, and workspaces of tabsets that users can rearrange by dragging tabs.
Support
If you like this project there are several ways to support it:
Installation
Begin by installing the library from NPM:
npm install react-resizable-panels
TypeScript types
TypeScript definitions are included within the published dist folder
FAQs
Frequently asked questions can be found here.
Documentation
Documentation for this project is available at react-resizable-panels.vercel.app.
Group
A Group wraps a set of resizable Panel components.
Group content can be resized horizontally or vertically.
Group elements always include the following attributes:
<div data-group data-testid="group-id-prop" id="group-id-prop">
ℹ️ Test id can be used to narrow selection when unit testing.
Required props
None
Optional props
| Name |
Description |
| className |
CSS class name.
|
| id |
Uniquely identifies this group within an application.
Falls back to useId when not provided.
ℹ️ This value will also be assigned to the id and data-testid attributes (an explicit data-testid prop will take precedence).
|
| style |
CSS properties.
⚠️ The default inline styles cannot be overridden, except for overflow.
|
| children |
Panel and Separator components that comprise this group.
|
| defaultLayout |
Default layout for the Group.
ℹ️ This value allows layouts to be remembered between page reloads.
⚠️ Slight layout shift may occur when server-rendering panels with percentage-based default sizes.
Refer to the documentation for suggestions on how to minimize the impact of this.
|
| disableCursor |
This library sets custom mouse cursor styles to indicate drag state.
Use this prop to disable that behavior for Panels and Separators in this group.
|
| disabled |
Disable resize functionality.
|
| elementRef |
Ref attached to the root HTMLDivElement.
|
| groupRef |
Exposes the following imperative API:
getLayout(): Layout
setLayout(layout: Layout): Layout
ℹ️ The useGroupRef and useGroupCallbackRef hooks are exported for convenience in TypeScript projects.
|
| onLayoutChange |
Called when the Group's layout is changing.
⚠️ For layout changes caused by pointer events, this method is called each time the pointer is moved.
For most cases, it is recommended to use the onLayoutChanged callback instead.
|
| onLayoutChanged |
Called after the Group's layout has been changed.
ℹ️ For layout changes caused by pointer events, this callback is not called until the pointer has been released.
This callback is recommended for saving layouts to storage.
ℹ️ The second argument contains meta information about the layout change.
The isUserInteraction attribute signals whether the resize was caused by direct user input.
It is true for resizes caused by pointer or keyboard input
and false for other triggers (e.g. imperative API calls, initial mount, etc.)
The requestedLayout attribute is the layout before constraints were applied for the current Group size;
prefer it when persisting layouts.
|
| resizePreviewMode |
Controls whether pointer dragging updates Panel sizes immediately,
or renders overlay separator previews until the pointer is released.
Defaults to "panel" (immediate resizing); "separator" defers resizing until release.
Customize previews using the SeparatorOverlay component.
|
| resizeTargetMinimumSize |
Minimum size of the resizable hit target area (either Separator or Panel edge).
This threshold ensures targets are large enough to avoid mis-clicks.
- Coarse inputs (typically a finger on a touchscreen) have reduced accuracy;
to ensure accessibility and ease of use, hit targets should be larger to prevent mis-clicks.
- Fine inputs (typically a mouse) can be smaller
ℹ️ Apple interface guidelines suggest 20pt (27px) on desktops and 28pt (37px) for touch devices.
In practice this seems to be much larger than many of their own applications use though.
|
| orientation |
Specifies the resizable orientation ("horizontal" or "vertical"); defaults to "horizontal"
|
Panel
A Panel wraps resizable content and can be configured with min/max size constraints and collapsible behavior.
Panel size props can be in the following formats:
- Percentage of the parent Group (0…100)
- Pixels
- Relative font units (em, rem)
- Viewport relative units (vh, vw)
ℹ️ Numeric values are assumed to be pixels.
Strings without explicit units are assumed to be percentages (0%…100%).
Percentages may also be specified as strings ending with “%” (e.g. “33%”)
Pixels may also be specified as strings ending with the unit “px”.
Other units should be specified as strings ending with their CSS property units (e.g. 1rem, 50vh)
Panel elements always include the following attributes:
<div data-panel data-testid="panel-id-prop" id="panel-id-prop">
ℹ️ Test id can be used to narrow selection when unit testing.
⚠️ Panel elements must be direct DOM children of their parent Group elements.
Required props
None
Optional props
| Name |
Description |
| className |
CSS class name.
⚠️ Class is applied to nested HTMLDivElement to avoid styles that interfere with Flex layout.
|
| id |
Uniquely identifies this panel within the parent group.
Falls back to useId when not provided.
ℹ️ This prop is used to associate persisted group layouts with the original panel.
ℹ️ This value will also be assigned to the id and data-testid attributes (an explicit data-testid prop will take precedence).
|
| style |
CSS properties.
⚠️ The default inline styles cannot be overridden, except for overflow.
|
| collapsedSize |
Panel size when collapsed; defaults to 0%.
|
| collapsedThreshold |
Distance a collapsible panel must be resized past its minSize to collapse,
or past its collapsedSize to expand.
Defaults to half the distance between collapsedSize and minSize.
For example if a panel declares collapsedSize="5%", collapsedThreshold="5%", and minSize="25%",
it will collapse when resized below 20% and expand when resized above 10%.
ℹ️ Interpretation rules:
- Numbers are interpreted as pixels (e.g.
minSize={200} is 200 pixels)
- Strings without explicit units are interpreted as percentage (e.g.
minSize="50" is 50 percent)
- Use explicit units (e.g. "px", "%", "em", "rem", "vh", or "vw") to change interpretation
|
| collapsible |
This panel can be collapsed.
ℹ️ A collapsible panel will collapse when its size is less than the specified minSize
|
| defaultSize |
Default size of Panel within its parent group; default is auto-assigned based on the total number of Panels.
ℹ️ Interpretation rules:
- Numbers are interpreted as pixels (e.g.
defaultSize={200} is 200 pixels)
- Strings without explicit units are interpreted as percentage (e.g.
defaultSize="50" is 50 percent)
- Use explicit units (e.g. "px", "%", "em", "rem", "vh", or "vw") to change interpretation
⚠️ Percentage based sizes may cause slight layout shift when server-rendering.
For more information see the documentation.
|
| disabled |
When disabled, a panel cannot be resized either directly or indirectly (by resizing another panel).
|
| elementRef |
Ref attached to the root HTMLDivElement.
|
| groupResizeBehavior |
How should this Panel behave if the parent Group is resized?
Defaults to preserve-relative-size.
preserve-relative-size: Retain the current relative size (as a percentage of the Group)
preserve-pixel-size: Retain its current size (in pixels)
ℹ️ Panel min/max size constraints may impact this behavior.
⚠️ A Group must contain at least one Panel with preserve-relative-size resize behavior.
|
| maxSize |
Maximum size of Panel within its parent group; defaults to "100%".
ℹ️ Interpretation rules:
- Numbers are interpreted as pixels (e.g.
maxSize={200} is 200 pixels)
- Strings without explicit units are interpreted as percentage (e.g.
maxSize="50" is 50 percent)
- Use explicit units (e.g. "px", "%", "em", "rem", "vh", or "vw") to change interpretation
|
| minSize |
Minimum size of Panel within its parent group; defaults to 0%.
ℹ️ Interpretation rules:
- Numbers are interpreted as pixels (e.g.
minSize={200} is 200 pixels)
- Strings without explicit units are interpreted as percentage (e.g.
minSize="50" is 50 percent)
- Use explicit units (e.g. "px", "%", "em", "rem", "vh", or "vw") to change interpretation
|
| onResize |
Called when panel sizes change.
@param panelSize Panel size (both as a percentage of the parent Group and in pixels)
@param id Panel id (if one was provided as a prop)
@param prevPanelSize Previous panel size (will be undefined on mount)
|
| panelRef |
Exposes the following imperative API:
collapse(): void
expand(): void
getSize(): PanelSize
isCollapsed(): boolean
resize(size: number | string): void
ℹ️ The usePanelRef and usePanelCallbackRef hooks are exported for convenience in TypeScript projects.
|
Separator
Separators are not required but they are recommended as they improve keyboard accessibility.
⚠️ Separator elements must be direct DOM children of their parent Group elements.
Separator elements always include the following attributes:
<div data-separator data-testid="separator-id-prop" id="separator-id-prop" role="separator">
ℹ️ Test id can be used to narrow selection when unit testing.
ℹ️ In addition to the attributes shown above, separator also renders all required WAI-ARIA properties.
Required props
None
Optional props
| Name |
Description |
| className |
CSS class name.
ℹ️ Use the data-separator attribute for custom hover and active styles
⚠️ The following properties cannot be overridden: flex-grow, flex-shrink
|
| id |
Uniquely identifies the separator within the parent group.
Falls back to useId when not provided.
ℹ️ This value will also be assigned to the id and data-testid attributes (an explicit data-testid prop will take precedence).
|
| style |
CSS properties.
ℹ️ Use the data-separator attribute for custom hover and active styles
⚠️ The following properties cannot be overridden: flex-grow, flex-shrink
|
| disabled |
When disabled, the separator cannot be used to resize its neighboring panels.
ℹ️ The panels may still be resized indirectly (while other panels are being resized).
To prevent a panel from being resized at all, it needs to also be disabled.
|
| disableDoubleClick |
When true, double-clicking this Separator will not reset its Panel to its default size.
|
| elementRef |
Ref attached to the root HTMLDivElement.
|
| preview |
Overrides the Group default preview for this Separator when resizePreviewMode is "separator".
|
Grid
A Grid arranges resizable Cells in two dimensions.
Columns can be resized horizontally and rows can be resized vertically;
dragging the point where a column boundary and a row boundary intersect resizes both.
Size constraints (e.g. min/max size, collapsible) are specified per track (column or row),
using the same format as Panel props.
Cells can span multiple columns and/or rows.
Track boundaries cannot be resized alongside of a cell that spans across them.
Grid elements always include the following attributes:
<div data-grid data-testid="grid-id-prop" id="grid-id-prop">
ℹ️ Test id can be used to narrow selection when unit testing.
Required props
| Name |
Description |
| columns |
Grid columns; either the number of columns or an array of size constraints (one per column).
|
| rows |
Grid rows; either the number of rows or an array of size constraints (one per row).
|
Optional props
| Name |
Description |
| className |
CSS class name.
|
| id |
Uniquely identifies this grid within an application.
Falls back to useId when not provided.
ℹ️ This value will also be assigned to the id and data-testid attributes (an explicit data-testid prop will take precedence).
|
| style |
CSS properties.
⚠️ Grid template and display properties are managed by the Grid and cannot be overridden.
|
| children |
Cell and Gridline components that comprise this grid.
⚠️ Cell and Gridline elements must be direct DOM children of their parent Grid element.
|
| defaultLayout |
Default layout for either or both of the Grid's axes.
ℹ️ This value allows layouts to be remembered between page reloads.
|
| disableCursor |
This library sets custom mouse cursor styles to indicate drag state.
Use this prop to disable that behavior for this grid.
|
| disabled |
Disable resize functionality.
|
| elementRef |
Ref attached to the root HTMLDivElement.
|
| gridRef |
Exposes the following imperative API:
getLayout(): GridLayout
getTrackById(axis: "column" | "row", id: string | number): GridTrackImperativeHandle
getTrackByIndex(axis: "column" | "row", index: number): GridTrackImperativeHandle
setLayout(layout: Partial<GridLayout>): GridLayout
ℹ️ The useGridRef and useGridCallbackRef hooks are exported for convenience in TypeScript projects.
|
| onLayoutChange |
Called when the Grid's layout is changing.
⚠️ For layout changes caused by pointer events, this method is called each time the pointer is moved.
For most cases, it is recommended to use the onLayoutChanged callback instead.
|
| onLayoutChanged |
Called after the Grid's layout has been changed.
ℹ️ For layout changes caused by pointer events, this callback is not called until the pointer has been released.
This callback is recommended for saving layouts to storage.
|
| resizeTargetMinimumSize |
Minimum size of the resizable hit target area (either a Gridline or a Cell edge).
This threshold ensures targets are large enough to avoid mis-clicks.
ℹ️ Refer to the Group prop of the same name for more information.
|
Cell
A Cell occupies one or more tracks (columns and rows) within a Grid.
Cells are resized along with the tracks they occupy.
Cell elements always include the following attributes:
<div data-cell data-testid="cell-id-prop" id="cell-id-prop">
ℹ️ Test id can be used to narrow selection when unit testing.
⚠️ Cell elements must be direct DOM children of their parent Grid elements.
Required props
| Name |
Description |
| column |
Index of the (first) column this cell occupies.
|
| row |
Index of the (first) row this cell occupies.
|
Optional props
| Name |
Description |
| className |
CSS class name.
|
| id |
Uniquely identifies this cell within the parent grid.
Falls back to useId when not provided.
ℹ️ This value will also be assigned to the id and data-testid attributes (an explicit data-testid prop will take precedence).
|
| style |
CSS properties.
⚠️ Grid placement properties are managed by the Cell and cannot be overridden.
|
| children |
Cell contents.
|
| columnSpan |
Number of columns this cell spans; defaults to 1.
|
| elementRef |
Ref attached to the root HTMLDivElement.
|
| rowSpan |
Number of rows this cell spans; defaults to 1.
|
Gridline
Resizes the columns (or rows) of a Grid.
For example:
// Rendered between columns 0 and 1 and spans all rows
<Gridline type="column" column={1} />
// Rendered between rows 0 and 1 and spans all columns
<Gridline type="row" row={1} />
// Rendered between columns 0 and 1 alongside of row 2 only
<Gridline type="column" column={1} row={2} rowSpan={1} />
A gridline should not be rendered alongside of a Cell that spans across its boundary
(this includes disabled gridlines; in development builds, an error will be logged to the console);
render multiple gridlines along the same boundary instead (e.g. before and after the spanning Cell).
ℹ️ Once a boundary contains a gridline, it can only be resized using gridlines;
the parts of the boundary that aren’t alongside of a gridline can’t be dragged.
Where column and row gridlines intersect, dragging resizes both axes.
Gridlines are not required but they are recommended as they improve keyboard accessibility.
Gridline elements always include the following attributes:
<div aria-orientation="vertical" data-separator role="separator">
ℹ️ Column gridlines are vertical (aria-orientation="vertical") and row gridlines are horizontal (aria-orientation="horizontal").
ℹ️ In addition to the attributes shown above, gridlines also render all required WAI-ARIA properties.
⚠️ Gridline elements must be direct DOM children of their parent Grid elements.
ℹ️ Gridlines rendered by another component (rather than directly within the Grid) aren’t detected until they mount, so server-rendered layouts may shift slightly during hydration.
Required props
| Name |
Description |
| type |
Column gridlines are vertical; they resize the columns on either side of them.
Row gridlines are horizontal; they resize the rows on either side of them.
|
Optional props
| Name |
Description |
| children |
Gridline contents (e.g. a drag handle icon).
|
| className |
CSS class name.
ℹ️ Use the data-separator attribute for custom hover and active styles
|
| disabled |
When disabled, the gridline cannot be used to resize its neighboring tracks.
ℹ️ The tracks may still be resized indirectly (e.g. by an intersecting gridline or another boundary).
To prevent a track from being resized at all, it needs to also be disabled.
|
| elementRef |
Ref attached to the root HTMLDivElement.
|
| style |
CSS properties.
⚠️ Grid placement properties are managed by the gridline and cannot be overridden.
|
| column |
When type is "column", the gridline is rendered along the leading (left) edge of this column
(between it and the previous column); must be greater than 0 and less than the number of columns.
When type is "row", index of the first column the gridline is rendered alongside of; defaults to 0.
|
| row |
When type is "column", index of the first row the gridline is rendered alongside of; defaults to 0.
When type is "row", the gridline is rendered along the leading (top) edge of this row
(between it and the previous row); must be greater than 0 and less than the number of rows.
|
| rowSpan |
Number of rows a column gridline spans; defaults to all rows (starting from row).
ℹ️ Gridlines can span a subset of rows in order to avoid cells that span across the boundary they sit on;
multiple gridlines can be rendered along the same boundary (e.g. above and below a spanning cell).
|
| columnSpan |
Number of columns a row gridline spans; defaults to all columns (starting from column).
ℹ️ Gridlines can span a subset of columns in order to avoid cells that span across the boundary they sit on;
multiple gridlines can be rendered along the same boundary (e.g. before and after a spanning cell).
|
Workspace
A Workspace arranges tabsets that users can rearrange by dragging tabs:
between tabsets, within a tabset’s list of tabs, or onto the edge of a tabset to split it.
Tabsets can be resized and maximized.
The layout is described by a serializable model (see WorkspaceModel).
Workspaces are uncontrolled: provide an initial model with the defaultModel prop, save changes from the onModelChanged callback,
and make changes using the imperative API (see WorkspaceImperativeHandle).
ℹ️ Tab content is not remounted when a tab is moved.
Its elements are moved within the document, though, which resets some browser state (e.g. iframes are reloaded).
Workspace elements always include the following attributes:
<div data-workspace data-testid="workspace-id-prop" id="workspace-id-prop">
ℹ️ Test id can be used to narrow selection when unit testing.
Required props
| Name |
Description |
| defaultModel |
Initial layout of the workspace.
ℹ️ Splits and tabsets may omit their ids; they're assigned ids based on their position (see WorkspaceModelInput).
ℹ️ This value is only used when the Workspace mounts; use the imperative setModel method to replace it later.
|
| renderTabContent |
Content of a tab.
ℹ️ Content is only re-rendered when its tab changes or this function does;
a function created while rendering (e.g. an inline arrow function) re-renders the content of every tab whenever the Workspace's parent re-renders,
so it should be memoized (e.g. with useCallback) when tab content is expensive to render.
|
Optional props
| Name |
Description |
| className |
CSS class name.
|
| id |
Uniquely identifies this workspace within an application.
Falls back to useId when not provided.
ℹ️ This value will also be assigned to the id and data-testid attributes (an explicit data-testid prop will take precedence).
|
| style |
CSS properties.
|
| classNames |
CSS class names for the elements the workspace renders within its root element:
tabset: root element of a tabset (data-tabset)
header: contains a tabset's tab list and toolbar (data-tabset-header)
tabList: contains a tabset's tabs (data-tab-list)
tab: passed to renderTab with the rest of a tab's props (data-tab)
toolbar: contains the content returned by renderTabsetToolbar (data-tabset-toolbar)
tabPanels: contains a tabset's tab content (data-tab-panels)
tabContent: the element each tab's content is rendered into (data-tab-content)
dropIndicator: shows where a dragged tab will be dropped within a tabset's panels, or at an edge of the workspace (data-drop-indicator)
dragPreview: follows the pointer while a tab or tabset is dragged (data-drag-preview)
ℹ️ Elements expose their state as data attributes (e.g. data-tab-selected, or data-tabset-dragging while a tabset is dragged), which can be used for styling.
Elements within a collapsed tabset have a data-tabset-collapsed attribute.
Elements within a tabset also have a data-tab-placement attribute (see tabPlacement).
ℹ️ The drop indicator is the same element for the whole drag (rendered within the workspace's root element),
so it can be animated between regions and tabsets (e.g. transition: inset 250ms).
Its data-region attribute is the region of a tabset's panels it covers, or its data-edge attribute is the edge of the workspace it's at;
while a tab isn't over either, it has neither and isn't shown (opacity: 0).
ℹ️ Like the render props, this object is part of what tabsets re-render for;
in large workspaces, define it outside of the component (or memoize it) rather than inline.
|
| disabled |
Locks the arrangement: tabs cannot be resized, dragged, dropped, or closed by the user.
Selecting tabs and maximizing tabsets still work.
ℹ️ This prop overrides the disableClose and disableDrag flags of individual tabs.
|
| disableDragBetweenApps |
Keeps drags between workspaces (see dragGroup) within this copy of the application:
tabs dragged from this workspace can't be dropped into other copies of the application (e.g. the application loaded in another browser window or tab), and tabs dragged from other copies can't be dropped into this workspace.
Workspaces in popout windows rendered by this copy of the application (with portals) are still part of the group.
Defaults to false, so that workspaces with the same dragGroup in other copies of the application from the same origin can exchange tabs.
|
| disableDrop |
Prevents tabs (and tabsets) from being dropped onto some (or all) targets.
Functions are called when the target under the pointer changes;
returning true rejects the target.
ℹ️ While a tabset is dragged, this function is called for each of its tabs (see DisableDropArgs),
so restrictions on where tabs can be dropped apply to dragged tabsets too.
ℹ️ Tabs can also be dropped at the edges of the workspace (beside all of the other tabsets), within a few pixels of the edges of its layout
(except over tabset headers, where the tab lists are) or within its root element's padding.
These targets have an edge rather than a tabsetId; disableDrop={({ target }) => "edge" in target} turns them off.
|
| dragGroup |
Lets tabs (and tabsets) be dragged between workspaces with the same dragGroup,
including workspaces in popout windows (opened by the application and rendered into with a portal)
and in other copies of the application from the same origin, e.g. the application loaded in another browser window or tab (see disableDragBetweenApps).
Dropping one into another workspace moves it there, keeping its id and data;
both workspaces report the change to onModelChanged with the "transfer" reason.
Mouse drags use the browser's drag and drop when this prop is set, since pointer events can't follow the pointer into another window.
Touch drags still use pointer events, so they can't leave the window.
ℹ️ Tab ids must be unique within the group; a tab can't be dropped into a workspace that already has a tab with its id (and a tabset with the keepWhenEmpty flag can't be dragged to another workspace).
A tab dragged to another workspace is rendered by that workspace, so its content is mounted again.
⚠️ A tab dragged to another copy of the application is sent there with the structured clone algorithm (like postMessage), so its data must be cloneable (e.g. no functions);
tabs whose data can't be cloned (and tabsets containing them) can only be dragged within their copy of the application.
Copies loaded at different times may be running different versions of the application, so the other copy may need to handle tab data it doesn't recognize.
⚠️ Tabs (and tabsets) can still be torn off (see onTearOff), but some browsers (e.g. Safari) block popup windows opened at the end of a drag that uses the browser's drag and drop.
|
| elementRef |
Ref attached to the root HTMLDivElement.
|
| hiddenTabBehavior |
What happens to the content of tabs that are not selected.
Can be a function to choose per tab (e.g. based on its data).
"keep-mounted": content stays mounted (and its effects keep running)
"activity": content stays mounted but is rendered within a hidden React <Activity> boundary, so its effects are unmounted;
requires React 19.2 (falls back to "keep-mounted" otherwise)
"unmount": content is unmounted
ℹ️ Moving a tab never remounts its content.
⚠️ Its React state is preserved, but its elements are moved within the document, which resets some browser state:
iframes are reloaded, playing media is paused, and focused elements are blurred.
|
| onModelChanged |
Called after the model has changed (e.g. a tab was moved, selected, or closed, or a tabset was resized).
ℹ️ For changes caused by pointer events, this callback is not called until the pointer has been released.
This callback is recommended for saving models to storage.
|
| onTearOff |
Called when a tab (or a whole tabset) is dropped outside of the window, e.g. to open it in a popup window.
Return true to accept it, which removes it from this workspace (reported to onModelChanged with the "tear-off" reason);
otherwise nothing changes.
Tabs and tabsets can only be torn off if they could be dragged, and tabsets with the keepWhenEmpty flag can't be torn off.
Without this prop, dropping a tab outside of the window does nothing.
⚠️ The Workspace can't tell whether the application showed the tab, so check whether window.open returned null (because the popup was blocked)
and return false then to keep the tab; returning true removes it even if nothing shows it.
ℹ️ This is called while the release of the pointer is being handled (which browsers treat as user input), so a popup can be opened from it.
With the dragGroup prop, a tab is torn off when it's dropped outside of every window in the group; the end of those drags isn't treated as user input,
so browsers block popups opened then unless the drag started a few seconds earlier at most (and Safari blocks them always).
|
| renderDragPreview |
Content of the element that follows the pointer while a tab is being dragged.
Defaults to the tab's title (or id).
ℹ️ The element has a data-tear-off attribute while releasing the pointer would tear off the tab (see onTearOff).
|
| renderTabsetDragPreview |
Content of the element that follows the pointer while a whole tabset is being dragged.
Defaults to the title (or id) of its selected tab followed by the number of other tabs being dragged (e.g. "One (+2)"), or the selected tab's renderDragPreview when that prop is set, or the tabset's id if it has no tabs.
ℹ️ The element has a data-drag-type attribute: "tabset" while a tabset is dragged, and "tab" while a tab is.
It also has a data-tear-off attribute while releasing the pointer would tear off the tabset (see onTearOff).
|
| renderEmptyTabset |
Content shown in the panels of a tabset that has no tabs (e.g. "Drag a tab here"):
the root tabset of an empty workspace, or a tabset with the keepWhenEmpty flag.
|
| renderSeparator |
Separator rendered between the children of a split.
Should return a Separator (or null for no separator); defaults to an unstyled Separator.
ℹ️ Without separators, tabsets can still be resized by dragging their edges (like Panels in a Group without separators),
but separators are recommended: they can be resized with the keyboard,
and an edge's hit area can overlap the tabs beside it (pressing there resizes the tabset rather than dragging the tab).
|
| renderTab |
Renders a tab (within its tabset's tab list).
Spread props onto the returned element:
they make it a tab (its role and ARIA attributes, keyboard and pointer handling, and data attributes),
and attach a ref that dragging and keyboard focus depend on.
renderTab={(tab, props) => (
<div {...props}>
{tab.title}
<TabCloseButton />
</div>
)}
Individual props can be overridden or wrapped, e.g. to confirm before the Delete key closes a tab
(call props.onKeyDown for other keys).
⚠️ Merge className and style rather than replacing them (e.g. style={{ ...props.style, padding: 4 }}):
they include the tab entries of the classNames and styles props, and style includes the touch-action that touch dragging depends on.
ℹ️ Pointer and keyboard events from interactive descendants (button elements, role="button", or elements with a data-tab-ignore attribute) are ignored,
so clicking a button within a tab doesn't select or drag it.
ℹ️ When this prop is not provided, tabs show their title (or id) followed by a TabCloseButton.
|
| renderTabsetToolbar |
Content shown after a tabset's tab list (e.g. buttons to add a tab or maximize the tabset).
ℹ️ The useParentTabset and useParentTabsetState hooks can be used within this content.
|
| resizePreviewMode |
Controls whether pointer dragging updates sizes immediately,
or renders overlay separator previews until the pointer is released.
|
| serverRenderTabContent |
Render the content of selected tabs on the server.
Can be a function to choose per tab (e.g. based on its data).
Tab content is rendered through portals (so that moving a tab doesn't remount it), which React can't render on the server.
Content opted into server rendering is rendered inline instead, then moved into a portal once hydration has finished.
⚠️ That move remounts the content once (e.g. resetting its state and re-running its effects),
so this is best suited to content that is cheap to mount and benefits from being in the server-rendered HTML.
ℹ️ This prop has no effect for workspaces that are not server rendered.
|
| styles |
CSS properties for the elements the workspace renders within its root element (see classNames).
|
| tabPlacement |
Where tabs are placed relative to tab content.
Tabs placed on the left or right are stacked ("vertical"):
this determines how a dropped tab's position is found and which arrow keys move focus between tabs.
ℹ️ Elements within a tabset have a data-tab-placement attribute, which can be used for styling (e.g. rotating tabs on the left or right).
ℹ️ "left" and "right" are the start and end of the tabset (its header is rendered before or after its content),
so in a right-to-left layout (e.g. within dir="rtl") tabs placed on the "left" are on the right;
styles for them should use logical properties (e.g. border-inline-end rather than border-right).
ℹ️ Tabsets can override this with the tabPlacement field of their model node.
|
| tabRemovalSelectionBehavior |
Which tab is selected when a tabset's selected tab is removed (closed, or dragged to another tabset):
"adjacent": the tab after it (or before it, if it was the last tab)
"recent": the tabset's most recently selected tab (like an IDE's editor groups),
falling back to "adjacent" if none of its other tabs has been selected
ℹ️ In "recent" mode, each tabset's recently selected tabs are saved in the model (see TabsetNode.recentTabIds),
so they're restored with the rest of the layout.
|
| tabsetMinHeight |
Minimum height of each tabset's content area (not including its header).
ℹ️ Tabsets can override this with the minHeight field of their model node.
ℹ️ Interpretation rules:
- Strings must specify a unit: "px", "em", "rem", "vh", or "vw" (e.g.
tabsetMinHeight: "200px")
- Percentages (and strings without units) are not allowed
|
| tabsetMinWidth |
Minimum width of each tabset's content area (not including its header).
ℹ️ Tabsets can override this with the minWidth field of their model node.
ℹ️ Interpretation rules:
- Strings must specify a unit: "px", "em", "rem", "vh", or "vw" (e.g.
tabsetMinWidth: "200px")
- Percentages (and strings without units) are not allowed
|
| workspaceRef |
Exposes the imperative API (see WorkspaceImperativeHandle).
ℹ️ The useWorkspaceRef and useWorkspaceCallbackRef hooks are exported for convenience in TypeScript projects.
|
Closes the tab it is rendered within; render it within the element returned by the Workspace’s renderTab prop:
renderTab={(tab, props) => (
<div {...props}>
{tab.title}
<TabCloseButton>×</TabCloseButton>
</div>
)}
The button renders nothing if closing is disabled (by the tab’s disableClose flag or the Workspace’s disabled prop).
Its content defaults to “×” (e.g. it can be replaced with an icon),
and its default aria-label is “Close” followed by the tab’s title (or id).
Its children, className, style, and title can also be functions of its state (see TabCloseButtonState):
<TabCloseButton title={({ tabTitle }) => `Close ${tabTitle}`} />
To keep the tab open (e.g. to confirm unsaved changes first), call event.preventDefault() in an onClick handler:
<TabCloseButton
=> {
if (hasUnsavedChanges && !confirm("Discard unsaved changes?")) {
event.preventDefault();
}
}}
/>
ℹ️ This button is not focusable by default (tabIndex={-1}), since tabs shouldn’t contain focusable content;
keyboard users can close the focused tab with Delete or Backspace.
Required props
None
Optional props
| Name |
Description |
| children |
Content of the element, or a function that returns it (given the component's state).
|
| className |
Class name of the element, or a function that returns it (given the component's state).
|
| style |
Inline styles of the element, or a function that returns them (given the component's state).
|
| title |
Tooltip of the element, or a function that returns it (given the component's state).
|
评论