Show · OverflowList

OverflowList

OverflowList is a behavior component used to take list of items and display as many items as can fit inside itself. Overflowed items that do not fit are collected and rendered by callback function. The visible items will be recomputed when a resize is detected.

Demos

How to import

<script setup lang="ts">
    import { OverflowList } from '@fibrous/semi-ui-vue';
</script>

Collapse Mode - Simple

You could use renderMode="collapse" (default) to render items.

items holds data only, never nodes. Render each visible item with the #item="{ item, index }" slot and the overflowing items with the #overflow="{ items, position }" slot; in collapse mode it is called once, and items are the items that do not fit.

0100


Code
<script setup lang="ts">
    import { ref, type Component } from 'vue';
    import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-vue';
    import { OverflowList, Slider, Tag } from '@fibrous/semi-ui-vue';

    interface Item {
        key: string;
    }

    const icons: Record<string, Component> = {
        alarm: IconAlarm,
        bookmark: IconBookmark,
        camera: IconCamera,
        duration: IconDuration,
        edit: IconEdit,
        folder: IconFolder,
    };
    const items: Item[] = Object.keys(icons).map((key) => ({ key }));
    const width = ref(100);

    const changeWidth = (value: number | number[]) => {
        if (typeof value === 'number') width.value = value;
    };
</script>

<template>
    <div>
        <Slider aria-label="Container width" :modelValue="width" :step="1" @update:modelValue="changeWidth" />
        <br />
        <br />
        <div :style="{ width: `${width}%` }">
            <OverflowList :items="items">
                <template #item="{ item }">
                    <Tag color="blue" :style="{ marginRight: '8px', flex: '0 0 auto' }">
                        <component :is="icons[item.key]" :style="{ marginRight: '4px' }" />
                        <span>{{ item.key }}</span>
                    </Tag>
                </template>
                <template #overflow="{ items: hidden }">
                    <Tag v-if="hidden.length" :style="{ flex: '0 0 auto', fontVariantNumeric: 'tabular-nums' }"> +{{ hidden.length }} </Tag>
                </template>
            </OverflowList>
        </div>
    </div>
</template>

Collapse Mode - Direction

collapse mode supports two collapseFrom directions: start and end (default).

0100


Code
<script setup lang="ts">
    import { ref, type Component } from 'vue';
    import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-vue';
    import { OverflowList, Slider, Tag } from '@fibrous/semi-ui-vue';

    interface Item {
        key: string;
    }

    const icons: Record<string, Component> = {
        alarm: IconAlarm,
        bookmark: IconBookmark,
        camera: IconCamera,
        duration: IconDuration,
        edit: IconEdit,
        folder: IconFolder,
    };
    const items: Item[] = Object.keys(icons).map((key) => ({ key }));
    const width = ref(100);

    const changeWidth = (value: number | number[]) => {
        if (typeof value === 'number') width.value = value;
    };
</script>

<template>
    <div>
        <Slider aria-label="Container width" :modelValue="width" :step="1" @update:modelValue="changeWidth" />
        <br />
        <br />
        <div :style="{ width: `${width}%` }">
            <OverflowList collapseFrom="start" :items="items">
                <template #item="{ item }">
                    <Tag color="blue" :style="{ marginRight: '8px', flex: '0 0 auto' }">
                        <component :is="icons[item.key]" :style="{ marginRight: '4px' }" />
                        <span>{{ item.key }}</span>
                    </Tag>
                </template>
                <template #overflow="{ items: hidden }">
                    <Tag v-if="hidden.length" :style="{ marginRight: '8px', flex: '0 0 auto', fontVariantNumeric: 'tabular-nums' }"> +{{ hidden.length }} </Tag>
                </template>
            </OverflowList>
        </div>
    </div>
</template>

Collapse Mode - Visible

collapse mode supports to set up minimum visible items that will not be collected.

0100


Code
<script setup lang="ts">
    import { ref, type Component } from 'vue';
    import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-vue';
    import { OverflowList, Slider, Tag } from '@fibrous/semi-ui-vue';

    interface Item {
        key: string;
    }

    const icons: Record<string, Component> = {
        alarm: IconAlarm,
        bookmark: IconBookmark,
        camera: IconCamera,
        duration: IconDuration,
        edit: IconEdit,
        folder: IconFolder,
    };
    const items: Item[] = Object.keys(icons).map((key) => ({ key }));
    const width = ref(100);

    const changeWidth = (value: number | number[]) => {
        if (typeof value === 'number') width.value = value;
    };
</script>

<template>
    <div>
        <Slider aria-label="Container width" :modelValue="width" :step="1" @update:modelValue="changeWidth" />
        <br />
        <br />
        <div :style="{ width: `${width}%` }">
            <OverflowList :items="items" :minVisibleItems="3">
                <template #item="{ item }">
                    <Tag color="blue" :style="{ marginRight: '8px', flex: '0 0 auto' }">
                        <component :is="icons[item.key]" :style="{ marginRight: '4px' }" />
                        <span>{{ item.key }}</span>
                    </Tag>
                </template>
                <template #overflow="{ items: hidden }">
                    <Tag v-if="hidden.length" :style="{ flex: '0 0 auto', fontVariantNumeric: 'tabular-nums' }"> +{{ hidden.length }} </Tag>
                </template>
            </OverflowList>
        </div>
    </div>
</template>

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.

In scroll mode #overflow is called once per side, with position set to start or end and items being the items scrolled out on that side.

0100


+0
alarm
bookmark
camera
duration
edit
folder
+0
Code
<script setup lang="ts">
    import { ref, type Component } from 'vue';
    import { IconAlarm, IconBookmark, IconCamera, IconDuration, IconEdit, IconFolder } from '@fibrous/semi-icons-vue';
    import { OverflowList, Slider, Tag } from '@fibrous/semi-ui-vue';

    interface Item {
        key: string;
    }

    const icons: Record<string, Component> = {
        alarm: IconAlarm,
        bookmark: IconBookmark,
        camera: IconCamera,
        duration: IconDuration,
        edit: IconEdit,
        folder: IconFolder,
    };
    const items: Item[] = Object.keys(icons).map((key) => ({ key }));
    const width = ref(100);

    const changeWidth = (value: number | number[]) => {
        if (typeof value === 'number') width.value = value;
    };
</script>

<template>
    <div>
        <Slider aria-label="Container width" :modelValue="width" :step="1" @update:modelValue="changeWidth" />
        <br />
        <br />
        <div :style="{ width: `${width}%` }">
            <OverflowList :items="items" renderMode="scroll">
                <template #item="{ item }">
                    <Tag color="blue" :style="{ marginRight: '8px', flex: '0 0 auto' }">
                        <component :is="icons[item.key]" :style="{ marginRight: '4px' }" />
                        <span>{{ item.key }}</span>
                    </Tag>
                </template>
                <template #overflow="{ items: hidden }">
                    <Tag
                        :style="{
                            marginRight: '8px',
                            marginLeft: '8px',
                            flex: '0 0 auto',
                            fontVariantNumeric: 'tabular-nums',
                        }"
                    >
                        +{{ hidden.length }}
                    </Tag>
                </template>
            </OverflowList>
        </div>
    </div>
</template>

API Reference

Props

PropertyDescriptionTypeDefault
collapseFromCollapse direction in collapse mode: start or end."start" | "end"semiDefault("OverflowList", "collapseFrom", "end")
itemsThe items to render. They are data, not nodes; scroll mode requires a key on each item.T[]semiGlobalDefault("OverflowList", "items")
itemKeyProperty name of each item's key, or a function returning it. Defaults to the key property, then the item's position in items.TypeOverflowListKey | ((item: T) => OverflowListKey)undefined
minVisibleItemsMinimum number of visible items in collapse mode.numbersemiDefault("OverflowList", "minVisibleItems", 0)
overflowRenderDirectionWhere scroll mode renders the overflow nodes: both, start or end. Used by Tabs, not meant for end users."start" | "end" | "both"semiDefault("OverflowList", "overflowRenderDirection", "both")
renderModeRender mode: collapse or scroll."collapse" | "scroll"semiDefault("OverflowList", "renderMode", "collapse")
thresholdVisible ratio at which scroll mode reports an item as overflowing.numbersemiDefault("OverflowList", "threshold", 0.75)
wrapperClassNameClass name of the scroll wrapper in scroll mode.stringsemiGlobalDefault("OverflowList", "wrapperClassName")
wrapperPropsOther attributes of the scroll wrapper in scroll mode, such as a role that owns the visible items.Type(HTMLAttributes & Record<string, unknown>)semiGlobalDefault("OverflowList", "wrapperProps")
wrapperStyleStyle of the scroll wrapper in scroll mode.StyleValuesemiGlobalDefault("OverflowList", "wrapperStyle")

Events

EventDescriptionCallback parameters
overflowEmitted in collapse mode when the overflowing items change; the argument is an empty array when everything fits.[overflowItems: T[]]
intersectEmitted in scroll mode when the intersection state of the items changes.Type[res: Record<string, IntersectionObserverEntry>]
visibleStateChangeEmitted in scroll mode when the visible or hidden state of the items changes.Type[visibleState: Map<string, boolean>]

Slots

SlotDescriptionScope parameters
itemContent of one visible item, with the item and its position in items.TypeOverflowListItemSlotProps<T>
overflowContent for the overflowing items. Collapse mode calls it once with the items that do not fit; scroll mode calls it once per side, with position set to start or end and the items scrolled out on that side.TypeOverflowListOverflowSlotProps<T>

Exposes

NameDescriptionType
None

class, style and native attributes such as aria-* land on the root element through attrs; pass the scroll wrapper's class, style and other attributes with wrapperClassName, wrapperStyle and wrapperProps.

Accessibility

ARIA

  • When aria-label or aria-labelledby is passed, the root element gets role="group" so the group of items has a readable name; without them the root has no role