Demos
How to import
import { OverflowList } from '@fibrous/semi-ui-react';
Collapse Mode - Simple
You could use renderMode="collapse" (default) to render items.
Code
import { useState, type ReactNode } from 'react';
import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-react';
import { OverflowList, Tag, Slider } from '@fibrous/semi-ui-react';
interface Item {
icon: ReactNode;
key: string;
}
export default function OverflowListDemo() {
const [width, setWidth] = useState(100);
const renderOverflow = (items: Item[]) => {
return items.length ? <Tag style={{ flex: '0 0 auto', fontVariantNumeric: 'tabular-nums' }}>+{items.length}</Tag> : null;
};
const renderItem = (item: Item) => {
return (
<Tag color="blue" key={item.key} style={{ marginRight: 8, flex: '0 0 auto' }}>
{item.icon}
{item.key}
</Tag>
);
};
const items: Item[] = [
{ icon: <IconAlarm style={{ marginRight: 4 }} />, key: 'alarm' },
{ icon: <IconBookmark style={{ marginRight: 4 }} />, key: 'bookmark' },
{ icon: <IconCamera style={{ marginRight: 4 }} />, key: 'camera' },
{ icon: <IconDuration style={{ marginRight: 4 }} />, key: 'duration' },
{ icon: <IconEdit style={{ marginRight: 4 }} />, key: 'edit' },
{ icon: <IconFolder style={{ marginRight: 4 }} />, key: 'folder' },
];
return (
<div>
<Slider aria-label="Container width" step={1} value={width} onChange={(value) => typeof value === 'number' && setWidth(value)} />
<br />
<br />
<div style={{ width: `${width}%` }}>
<OverflowList items={items} overflowRenderer={renderOverflow} visibleItemRenderer={renderItem} />
</div>
</div>
);
}Collapse Mode - Direction
collapse mode supports two collapseFrom directions: start and end (default).
Code
import { useState, type ReactNode } from 'react';
import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-react';
import { OverflowList, Tag, Slider } from '@fibrous/semi-ui-react';
interface Item {
icon: ReactNode;
key: string;
}
export default function OverflowListDemo() {
const [width, setWidth] = useState(100);
const renderOverflow = (items: Item[]) => {
return items.length ? <Tag style={{ marginRight: 8, flex: '0 0 auto', fontVariantNumeric: 'tabular-nums' }}>+{items.length}</Tag> : null;
};
const renderItem = (item: Item) => {
return (
<Tag color="blue" key={item.key} style={{ marginRight: 8, flex: '0 0 auto' }}>
{item.icon}
{item.key}
</Tag>
);
};
const items: Item[] = [
{ icon: <IconAlarm style={{ marginRight: 4 }} />, key: 'alarm' },
{ icon: <IconBookmark style={{ marginRight: 4 }} />, key: 'bookmark' },
{ icon: <IconCamera style={{ marginRight: 4 }} />, key: 'camera' },
{ icon: <IconDuration style={{ marginRight: 4 }} />, key: 'duration' },
{ icon: <IconEdit style={{ marginRight: 4 }} />, key: 'edit' },
{ icon: <IconFolder style={{ marginRight: 4 }} />, key: 'folder' },
];
return (
<div>
<Slider aria-label="Container width" step={1} value={width} onChange={(value) => typeof value === 'number' && setWidth(value)} />
<br />
<br />
<div style={{ width: `${width}%` }}>
<OverflowList items={items} collapseFrom="start" overflowRenderer={renderOverflow} visibleItemRenderer={renderItem} />
</div>
</div>
);
}Collapse Mode - Visible
collapse mode supports to set up minimum visible items that will not be collected.
Code
import { useState, type ReactNode } from 'react';
import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-react';
import { OverflowList, Tag, Slider } from '@fibrous/semi-ui-react';
interface Item {
icon: ReactNode;
key: string;
}
export default function OverflowListDemo() {
const [width, setWidth] = useState(100);
const renderOverflow = (items: Item[]) => {
return items.length ? <Tag style={{ flex: '0 0 auto', fontVariantNumeric: 'tabular-nums' }}>+{items.length}</Tag> : null;
};
const renderItem = (item: Item) => {
return (
<Tag color="blue" key={item.key} style={{ marginRight: 8, flex: '0 0 auto' }}>
{item.icon}
{item.key}
</Tag>
);
};
const items: Item[] = [
{ icon: <IconAlarm style={{ marginRight: 4 }} />, key: 'alarm' },
{ icon: <IconBookmark style={{ marginRight: 4 }} />, key: 'bookmark' },
{ icon: <IconCamera style={{ marginRight: 4 }} />, key: 'camera' },
{ icon: <IconDuration style={{ marginRight: 4 }} />, key: 'duration' },
{ icon: <IconEdit style={{ marginRight: 4 }} />, key: 'edit' },
{ icon: <IconFolder style={{ marginRight: 4 }} />, key: 'folder' },
];
return (
<div>
<Slider aria-label="Container width" step={1} value={width} onChange={(value) => typeof value === 'number' && setWidth(value)} />
<br />
<br />
<div style={{ width: `${width}%` }}>
<OverflowList items={items} minVisibleItems={3} overflowRenderer={renderOverflow} visibleItemRenderer={renderItem} />
</div>
</div>
);
}Scroll Mode
You could use renderMode="scroll" for a scrollable list.
If you need certain element in the list to scrollIntoView, use document.querySelector(`.item-cls[data-scrollkey="${key}"] to select to corresponding DOM.
Code
import { useState, type ReactNode } from 'react';
import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-react';
import { OverflowList, Tag, Slider } from '@fibrous/semi-ui-react';
interface Item {
icon: ReactNode;
key: string;
}
export default function OverflowListDemo() {
const [width, setWidth] = useState(100);
const renderHiddenCount = (hiddenItems: Item[]) => <Tag style={{ marginRight: 8, marginLeft: 8, flex: '0 0 auto', fontVariantNumeric: 'tabular-nums' }}>+{hiddenItems.length}</Tag>;
const renderOverflow = ([start, end]: [Item[], Item[]]): [ReactNode, ReactNode] => [renderHiddenCount(start), renderHiddenCount(end)];
const renderItem = (item: Item) => {
return (
<Tag key={item.key} color="blue" style={{ marginRight: 8, flex: '0 0 auto' }}>
{item.icon}
{item.key}
</Tag>
);
};
const items: Item[] = [
{ icon: <IconAlarm style={{ marginRight: 4 }} />, key: 'alarm' },
{ icon: <IconBookmark style={{ marginRight: 4 }} />, key: 'bookmark' },
{ icon: <IconCamera style={{ marginRight: 4 }} />, key: 'camera' },
{ icon: <IconDuration style={{ marginRight: 4 }} />, key: 'duration' },
{ icon: <IconEdit style={{ marginRight: 4 }} />, key: 'edit' },
{ icon: <IconFolder style={{ marginRight: 4 }} />, key: 'folder' },
];
return (
<div>
<Slider aria-label="Container width" step={1} value={width} onChange={(value) => typeof value === 'number' && setWidth(value)} />
<br />
<br />
<div style={{ width: `${width}%` }}>
<OverflowList items={items} renderMode="scroll" overflowRenderer={renderOverflow} visibleItemRenderer={renderItem} />
</div>
</div>
);
}API Reference
Props
| Property | Description | Type | Default |
|---|---|---|---|
| className | Class name of the root element. | string | - |
| collapseFrom | Collapse direction in collapse mode: start or end. | 'start' | 'end' | "end" |
| itemKey | Property name of each item's key, or a function returning it. Defaults to the key property, then the item's position in items. | Typestring | number | ((item: T) => string | number) | - |
| items | Items to render. They are data, not nodes; visibleItemRenderer renders them. Scroll mode requires a key on each item, the field named by itemKey when it is set. | TypeArray<T> | [] |
| minVisibleItems | Minimum number of visible items in collapse mode; these items are not collapsed even when they do not fit. | number | 0 |
| onIntersect | Called in scroll mode when the intersection state of the items changes, with each item's IntersectionObserverEntry keyed by its key. | Type(res: { [key: string]: IntersectionObserverEntry }) => void | - |
| onOverflow | Called in collapse mode when the overflowing items change, with an empty array once everything fits. | Type(overflowItems: Array<T>) => void | Type() => null |
| onVisibleStateChange | Called in scroll mode when the visible or hidden state of the items changes, with a Map keyed by item key. | Type(visibleState: Map<string, boolean>) => void | - |
| overflowRenderDirection | Where scroll mode renders the two overflow nodes: both, start or end. Used by Tabs, not meant for end users. | 'both' | 'start' | 'end' | "both" |
| overflowRenderer | Renders the overflowing items. In collapse mode it receives the items that do not fit and returns one overflow node; in scroll mode it receives [start, end], the items scrolled out before and after the visible ones, and returns one node for each side. | Type((overflowItems: Array<T>) => ReactNode) | ((overflowItems: [Array<T>, Array<T>]) => [ReactNode, ReactNode]) | Type(): ReactElement => null |
| ref | Reference to the root element. | TypeReact.Ref<HTMLDivElement> | - |
| renderMode | Render mode: collapse or scroll. | 'collapse' | 'scroll' | "collapse" |
| style | Style of the root element. | CSSProperties | - |
| threshold | Visible ratio at which scroll mode reports an item's intersection. | number | 0.75 |
| visibleItemRenderer | Renders one visible item and returns its React element; index is the item's position in items. In scroll mode the element is observed and gets a data-scrollkey attribute. | Type(item: T, index: number) => ReactElement | Type(): ReactElement => null |
| wrapperClassName | Class name of the scroll wrapper in scroll mode. | string | - |
| wrapperProps | Other attributes of the scroll wrapper in scroll mode, such as a role that owns the visible items. Its className and style are overridden by wrapperClassName and wrapperStyle. | TypeHTMLAttributes<HTMLDivElement> | - |
| wrapperStyle | Style of the scroll wrapper in scroll mode, as a style object. | CSSProperties | - |
Other native attributes such as aria-*, id, data-* and onClick land on the root element.
Accessibility
ARIA
- When
aria-labeloraria-labelledbyis passed, the root element getsrole="group"so the group of items has a readable name; without them the root has no role