Show · ScrollList

ScrollList

Scroll through the list.

Demos

How to import

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

Basic Usage

The scrolling list provides a scrolling selection mode similar to the iOS operating system, while supporting scrolling to the specified window location selection and click selection.

Bind the selected item with v-model:selectedIndex; there is no uncontrolled mode. header and footer are string props; use the slots of the same name for custom content.

无限滚动列表
  • 上午
  • 下午
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, ScrollItem, ScrollList, type ScrollItemSelectData } from '@fibrous/semi-ui-vue';

    const ampms = [{ value: '上午' }, { value: '下午' }];
    const hours = Array.from({ length: 12 }, (_, index) => ({ value: index + 1 }));
    const minutes = Array.from({ length: 60 }, (_, index) => ({ value: index, disabled: index % 3 === 0 }));

    const selectIndex1 = ref(1);
    const selectIndex2 = ref(1);
    const selectIndex3 = ref(1);

    const onSelectHour = (data: ScrollItemSelectData) => {
        console.log('You have choose the hour for: ', data.value);
    };

    const onSelectMinute = (data: ScrollItemSelectData) => {
        console.log('You have choose the minute for: ', data.value);
    };

    const handleClose = () => {
        console.log('close');
    };
</script>

<template>
    <ScrollList header="无限滚动列表" :style="{ border: 'unset', boxShadow: 'unset' }">
        <ScrollItem v-model:selectedIndex="selectIndex1" aria-label="上午或下午" :cycled="false" :list="ampms" mode="wheel" :type="1" />
        <ScrollItem v-model:selectedIndex="selectIndex2" aria-label="小时" cycled :list="hours" mode="wheel" :type="2" @select="onSelectHour" />
        <ScrollItem v-model:selectedIndex="selectIndex3" aria-label="分钟" cycled :list="minutes" mode="wheel" :type="3" @select="onSelectMinute" />
        <template #footer>
            <Button size="small" type="primary" @click="handleClose">Ok</Button>
        </template>
    </ScrollList>
</template>

API Reference

ScrollList

Props

PropertyDescriptionTypeDefault
bodyHeightHeight of the list body.string | numbersemiGlobalDefault("ScrollList", "bodyHeight")
footerFooter text. The footer slot takes precedence when given.stringsemiGlobalDefault("ScrollList", "footer")
headerHeader text. The header slot takes precedence when given.stringsemiGlobalDefault("ScrollList", "header")

Events

EventDescriptionCallback parameters
None

Slots

SlotDescriptionScope parameters
defaultThe ScrollItem columns.any
footerCustom footer content.any
headerCustom header content.any

Exposes

NameDescriptionType
None

class, style and native attributes such as aria-* land on the root element through attrs.

ScrollItem

Props

PropertyDescriptionTypeDefault
cycledWhether the column cycles. In wheel mode the list scrolls without end; in both modes the arrow keys wrap around.booleansemiDefault("ScrollItem", "cycled", false)
listItems of the column.T[]semiGlobalDefault("ScrollItem", "list")
modeMode: normal or wheel."normal" | "wheel"semiDefault("ScrollItem", "mode", "wheel")
motionWhether to animate scrolling.booleansemiDefault("ScrollItem", "motion", true)
selectedIndexIndex of the selected item, used with v-model:selectedIndex. There is no uncontrolled mode.numbersemiGlobalDefault("ScrollItem", "selectedIndex")
transformFormats the text of the selected item; the text is undefined for an item without one. When omitted, text is shown, or value when there is no text. An item's own transform takes precedence.Type((value: T["value"], text?: string | undefined) => string)undefined
typeIdentifies the column to components such as TimePicker and DatePicker, not meant for end users.string | numbersemiGlobalDefault("ScrollItem", "type")

Events

EventDescriptionCallback parameters
update:selectedIndexEmitted when the selection changes, backing v-model:selectedIndex.[index: number]
selectEmitted when an item is selected, with the item's data plus the column's type and the item's index in list.Type[data: ScrollItemSelectData<T>]

Slots

SlotDescriptionScope parameters
None

Exposes

NameDescriptionType
None

aria-label, aria-labelledby and aria-describedby land on the list (role="listbox"); class, style and other attributes land on the root element.

ItemData

PropertiesInstructionstypeDefault
disabledWhether the item is prohibited or notboolean
textThe copy of each item.string
transformWhen the transformation is in the selected state, the return value is displayed as a copy, and if the ScrollItem component is passed at the same time, the transform method in ItemData will be selected first. When omitted, text is shown, or value when there is no text.(value: any, text: string | undefined) => string
valueThe value of each itemany

Methods

Call these through a template ref of ScrollItem, for example to realign the selected item after the container is resized.

NameDescription
scrollToIndex(selectedIndex?: number, duration?: number)Scrolls the list to the current selected item. selectedIndex has no effect yet and the target is always the item last selected. duration is the scroll animation duration in milliseconds, default 120

Accessibility

ARIA

  • When aria-label or aria-labelledby is passed, the root element of ScrollList gets role="group"
  • ScrollItem is a role="listbox" and supports aria-label, which indicates the label of the current column.
  • ScrollItem uses aria-disabled to indicate whether the item is disabled
  • ScrollItem uses aria-selected to indicate whether the item is selected
  • The copies that fill the wheel of a cycled column carry aria-hidden="true", so screen readers only read the real options

Keyboard and Focus

  • Each column is a listbox: focus it with Tab. Focus stays on the list and the selected item is exposed through aria-activedescendant; selection follows focus, and each selection fires the select callback
  • ArrowUp selects the previous item and ArrowDown the next one, skipping disabled items; Home selects the first item and End the last one
  • With cycled, the arrow keys wrap around at both ends in either mode; without it they stop at the ends
  • Typing characters selects the item whose text starts with them; typing the same character repeatedly moves on to the next match

Design Tokens

These are the component's internal Sass variables and cannot be overridden. To customize styles, override the --semi-* CSS variables (see the Design Token page) or write unlayered CSS rules.
Sass variableValueUsage
$transition_duration-scrollList_selected_item-bgvar(--semi-transition_duration-none)滚动列表选中选项-背景颜色-动画持续时间
$transition_function-scrollList_selected_item-bgvar(--semi-transition_function-easeOut)滚动列表选中选项-背景颜色-过渡曲线
$transition_delay-scrollList_selected_item-bg0ms滚动列表选中选项-背景颜色-延迟时间
$color-scrollList-bgvar(--semi-color-bg-3)滚动列表背景色
$color-scrollList-bordervar(--semi-color-border)滚动列表描边颜色
$color-scrollList_header-bgtransparent滚动列表 header 背景色
$color-scrollList_header-titlevar(--semi-color-text-0)滚动列表标题颜色
$color-scrollList_item-bgtransparent滚动列表选项背景色
$color-scrollList_item-textvar(--semi-color-text-0)滚动列表选项文字颜色
$color-scrollList_disabled_item-textvar(--semi-color-disabled-text)滚动列表选项背景色 - 禁用
$color-scrollList_item-text-hovervar(--semi-color-fill-1)滚动列表选项文字颜色 - 悬浮
$color-scrollList_item-bg-activevar(--semi-color-fill-2)滚动列表选项文字颜色 - 选中
$color-scrollList_selected_item-bgvar(--semi-color-primary-light-default)滚动列表选中选项背景颜色
$color-scrollList_selected_item-textvar(--semi-color-text-0)滚动列表选中选项文字颜色
$color-scrollList_selected_item-iconvar(--semi-color-text-2)滚动列表选中选项图标颜色
$color-scrollList_footer-bordervar(--semi-color-border)滚动列表底部描边颜色
$height-scrollList300px
$height-scrollList_item36px
$width-scrollList_item-border$border-thickness-control
$width-scrollList_item_sel_svg16px
$width-scrollList_item_wheel_selector-border$border-thickness-control
$height-scrollList_line1px
$width-scrollList_footer-border$border-thickness-control
$spacing-scrollList_header-paddingY0
$spacing-scrollList_header-paddingX16px
$spacing-scrollList_header_title-paddingY$spacing-base
$spacing-scrollList_header_title-paddingX0
$spacing-scrollList_body-paddingY0
$spacing-scrollList_body-paddingX16px
$spacing-scrollList_item_ul-padding0
$spacing-scrollList_item_ul-margin0
$spacing-scrollList_item_ul-paddingBottom($height-scrollList - $height-scrollList_item) * 0.5
$spacing-scrollList_item_sel_svg-marginRight12px
$spacing-scrollList_item_wheel_list_outer-paddingRight$height-scrollList_item * 0.5
$spacing-scrollList_item_wheel_list_shade_pre-marginTop-1 * ($height-scrollList_item * 0.5 + $border-thickness-control)
$spacing-scrollList_item_wheel_list_shade_post-marginTop$height-scrollList_item * 0.5 + $border-thickness-control
$spacing-scrollList_footer-padding10px
$radius-scrollListvar(--semi-border-radius-medium)
$font-scrollList_header_title-fontWeight$font-weight-bold
$font-scrollList_item_wheel_item_selected-fontWeight$font-weight-bold
$shadow-scrollListvar(--semi-shadow-elevated)