Clawscale

Overflow list

An OverflowList renders as many items as fit in its container and passes the rest to an overflow renderer. It recomputes when its size changes.

Usage#

import { OverflowList } from "@clawscale/react";
<OverflowList
  items={stages}
  visibleItemRenderer={(stage) => <Button key={stage} style={{ flexShrink: 0 }} text={stage} />}
  overflowRenderer={(hidden) => <Tag minimal>{hidden.length} more</Tag>}
/>

visibleItemRenderer runs once per visible item. Set a key on the element it returns. overflowRenderer runs once with all hidden items.

Items must keep their width. Buttons and tags shrink by default, which hides the overflow from the list. Give them flexShrink: 0.

Examples#

Collapse into a menu#

Hidden items go into a menu behind a button. collapseFrom={Boundary.END} hides items from the end. Drag the lower right corner of the box to resize it.

import { Boundary, Button, Menu, MenuItem, OverflowList, PopoverNext } from "@clawscale/react";

const STAGES = ["Extract", "Validate", "Deduplicate", "Enrich", "Join", "Aggregate", "Publish"];

export default function OverflowListBasic() {
  return (
    <div
      style={{
        border: "1px dashed var(--cs-color-border-strong)",
        maxWidth: "100%",
        minWidth: 96,
        overflow: "hidden",
        padding: 4,
        resize: "horizontal",
        width: 400,
      }}
    >
      <OverflowList
        items={STAGES}
        collapseFrom={Boundary.END}
        visibleItemRenderer={(stage) => <Button key={stage} style={{ flexShrink: 0 }} variant="minimal" text={stage} />}
        overflowRenderer={(hidden) => (
          <PopoverNext
            placement="bottom-end"
            content={
              <Menu>
                {hidden.map((stage) => (
                  <MenuItem key={stage} text={stage} />
                ))}
              </Menu>
            }
          >
            <Button variant="minimal" icon="more" aria-label={`${hidden.length} more stages`} />
          </PopoverNext>
        )}
      />
    </div>
  );
}

Collapse from the start#

Items collapse from the start by default, and the overflow renders before the visible items. Here the newest runs stay visible. minVisibleItems sets how many items never collapse.

#1275#1276#1277#1278#1279#1280#1281#1282#1283#1284
import { type Intent, OverflowList, Tag } from "@clawscale/react";

const RUNS: { id: number; intent: Intent }[] = [
  { id: 1275, intent: "success" },
  { id: 1276, intent: "success" },
  { id: 1277, intent: "danger" },
  { id: 1278, intent: "success" },
  { id: 1279, intent: "success" },
  { id: 1280, intent: "warning" },
  { id: 1281, intent: "success" },
  { id: 1282, intent: "success" },
  { id: 1283, intent: "danger" },
  { id: 1284, intent: "success" },
];

export default function OverflowListCollapseFrom() {
  return (
    <OverflowList
      items={RUNS}
      style={{ gap: 4, width: 280 }}
      overflowRenderer={(older) => (
        <Tag minimal style={{ flexShrink: 0 }}>
          {older.length} older
        </Tag>
      )}
      visibleItemRenderer={(run) => (
        <Tag key={run.id} minimal intent={run.intent} style={{ flexShrink: 0 }}>
          #{run.id}
        </Tag>
      )}
    />
  );
}

Props interface#

OverflowList measures itself with ResizeObserver. Set observeParents when a parent can resize without resizing the list.

interface OverflowListProps extends Props@clawscale/react
PropsDescription
alwaysRenderOverflow
boolean = false
Whether to force the overflowRenderer to always be called, even if there are zero items overflowing. This may be useful, for example, if your overflow renderer contains a Popover which you do not want to close as the list is resized.
className
string
A space-delimited list of class names to pass along to a child element.
Inherited from Props
collapseFrom
Boundary = Boundary.START
Which direction the items should collapse from: start or end of the children. This also determines whether overflowRenderer appears before (START) or after (END) the visible items.
itemsrequired
readonly T[]
All items to display in the list. Items that do not fit in the container will be rendered in the overflow instead.
minVisibleItems
number = 0
The minimum number of visible items that should never collapse into the overflow menu, regardless of DOM dimensions.
navigable
boolean = false
If true, the overflow list will be wrapped with a nav element.
navigationAriaLabel
string = ""
ARIA label to apply to the nav element. Only used if navigable is true.
observeParents
boolean = false
If true, all parent DOM elements of the container will also be observed. If changes to a parent's size is detected, the overflow will be recalculated.
onOverflow
(overflowItems: T[]) => void
Callback invoked when the overflowed items change. This is called once after the DOM has settled, rather that on every intermediate change. It is not invoked if resizing produces an unchanged overflow state.
overflowRendererrequired
(overflowItems: T[]) => React.ReactNode
Callback invoked to render the overflowed items. Unlike visibleItemRenderer, this prop is invoked once with all items that do not fit in the container.
style
React.CSSProperties
CSS properties to apply to the root element.
tagName
keyof React.JSX.IntrinsicElements = "div"
HTML tag name for the container element.
visibleItemRendererrequired
(item: T, index: number) => React.ReactNode
Callback invoked to render each visible item. Remember to set a key on the rendered element!