Demos
How to import
import { ScrollList, ScrollItem } from '@fibrous/semi-ui-react';
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.
无限滚动列表
- 上午
- 下午
- 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
import { useState } from 'react';
import { ScrollList, ScrollItem, Button, type ScrollListItem as Item } from '@fibrous/semi-ui-react';
const minutes = Array.from({ length: 60 }).map((_itm, index) => {
return {
value: index,
disabled: index % 3 === 2,
};
});
export default function ScrollListDemo() {
const [selectIndex1, setSelectIndex1] = useState(1);
const [selectIndex2, setSelectIndex2] = useState(1);
const [selectIndex3, setSelectIndex3] = useState(1);
const ampms = [
{
value: '上午',
},
{
value: '下午',
},
];
const hours = Array.from({ length: 12 }).map((_itm, index) => {
return {
value: index + 1,
};
});
const onSelectAP = (data: Item) => {
setSelectIndex1(data.index);
};
const onSelectHour = (data: Item) => {
console.log('You have choose the hour for: ', data.value);
setSelectIndex2(data.index);
};
const onSelectMinute = (data: Item) => {
console.log('You have choose the minute for: ', data.value);
setSelectIndex3(data.index);
};
const handleClose = () => {
console.log('close');
};
const renderFooter = () => {
return (
<Button size="small" type="primary" onClick={handleClose}>
Ok
</Button>
);
};
const scrollStyle = {
border: 'unset',
boxShadow: 'unset',
};
return (
<ScrollList style={scrollStyle} header="无限滚动列表" footer={renderFooter()}>
<ScrollItem aria-label="上午或下午" mode="wheel" cycled={false} list={ampms} type={1} selectedIndex={selectIndex1} onSelect={onSelectAP} />
<ScrollItem aria-label="小时" mode="wheel" cycled list={hours} type={2} selectedIndex={selectIndex2} onSelect={onSelectHour} />
<ScrollItem aria-label="分钟" mode="wheel" cycled list={minutes} type={3} selectedIndex={selectIndex3} onSelect={onSelectMinute} />
</ScrollList>
);
}API Reference
ScrollList
Props
| Property | Description | Type | Default |
|---|---|---|---|
| bodyHeight | Height of the list body; a number is in px. Unset, the stylesheet decides. | number | string | - |
| children | The ScrollItem columns. | React.ReactNode | - |
| className | Class name of the root element. | string | - |
| footer | Footer content; any ReactNode. | React.ReactNode | - |
| header | Header content; any ReactNode. | React.ReactNode | - |
| prefixCls | Class name prefix, semi-scrolllist by default. | string | - |
| ref | Reference to the root div element. | TypeReact.Ref<HTMLDivElement> | - |
| style | Style of the root element. | CSSProperties | - |
Other attributes such as aria-* land on the root element.
ScrollItem
Props
| Property | Description | Type | Default |
|---|---|---|---|
| className | Class name of the root element. | string | - |
| cycled | Whether the column cycles. In wheel mode the list scrolls without end; in both modes the arrow keys wrap around at both ends. | boolean | false |
| list | Items of the column. | T[] | [] |
| mode | Mode: normal or wheel. | string | "wheel" |
| motion | Whether to animate scrolling. | Motion | true |
| onSelect | Called when an item is selected, with the item's data plus the column's type and the item's index in list. The component keeps no selection state, so update selectedIndex in this callback. | Type(data: T & { type?: string | number; index: number }) => void | - |
| ref | Receives the ScrollItemHandle, whose scrollToIndex method is listed under Methods below. | TypeReact.Ref<ScrollItemHandle> | - |
| selectedIndex | Index of the selected item. There is no uncontrolled mode; update it in onSelect. | number | 0 |
| style | Style of the root element. | React.CSSProperties | - |
| transform | Formats the text of the selected item; the return value is displayed. When omitted, text is shown, or value when there is no text. An item's own transform takes precedence. | Type(value: any, text?: string) => string | - |
| type | Identifies the column to components such as TimePicker and DatePicker, not meant for end users. | string | number | - |
Methods
| Method | Description | Type |
|---|---|---|
| scrollToIndex | 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. | Type(selectedIndex?: number, duration?: number) => void |
aria-label, aria-labelledby and aria-describedby land on the list (role="listbox"); other attributes land on the root element.
ItemData
| Properties | Instructions | type | Default |
|---|---|---|---|
| disabled | Whether the item is prohibited or not | boolean | |
| text | The copy of each item. | string | |
| transform | When 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 | |
| value | The value of each item | any |
Methods
Call these through the ref of ScrollItem, for example to realign the selected item after the container is resized.
Accessibility
ARIA
- When
aria-labeloraria-labelledbyis passed, the root element ofScrollListgetsrole="group" ScrollItemis arole="listbox"and supportsaria-label, which indicates the label of the current column.ScrollItemusesaria-disabledto indicate whether the item is disabledScrollItemusesaria-selectedto indicate whether the item is selected- The copies that fill the wheel of a
cycledcolumn carryaria-hidden="true", so screen readers only read the real options
Keyboard and Focus
- Each column is a
listbox: focus it withTab. Focus stays on the list and the selected item is exposed througharia-activedescendant; selection follows focus, and each selection fires the select callback ArrowUpselects the previous item andArrowDownthe next one, skipping disabled items;Homeselects the first item andEndthe 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 variable | Value | Usage |
|---|---|---|
| $transition_duration-scrollList_selected_item-bg | var(--semi-transition_duration-none) | 滚动列表选中选项-背景颜色-动画持续时间 |
| $transition_function-scrollList_selected_item-bg | var(--semi-transition_function-easeOut) | 滚动列表选中选项-背景颜色-过渡曲线 |
| $transition_delay-scrollList_selected_item-bg | 0ms | 滚动列表选中选项-背景颜色-延迟时间 |
| $color-scrollList-bg | var(--semi-color-bg-3) | 滚动列表背景色 |
| $color-scrollList-border | var(--semi-color-border) | 滚动列表描边颜色 |
| $color-scrollList_header-bg | transparent | 滚动列表 header 背景色 |
| $color-scrollList_header-title | var(--semi-color-text-0) | 滚动列表标题颜色 |
| $color-scrollList_item-bg | transparent | 滚动列表选项背景色 |
| $color-scrollList_item-text | var(--semi-color-text-0) | 滚动列表选项文字颜色 |
| $color-scrollList_disabled_item-text | var(--semi-color-disabled-text) | 滚动列表选项背景色 - 禁用 |
| $color-scrollList_item-text-hover | var(--semi-color-fill-1) | 滚动列表选项文字颜色 - 悬浮 |
| $color-scrollList_item-bg-active | var(--semi-color-fill-2) | 滚动列表选项文字颜色 - 选中 |
| $color-scrollList_selected_item-bg | var(--semi-color-primary-light-default) | 滚动列表选中选项背景颜色 |
| $color-scrollList_selected_item-text | var(--semi-color-text-0) | 滚动列表选中选项文字颜色 |
| $color-scrollList_selected_item-icon | var(--semi-color-text-2) | 滚动列表选中选项图标颜色 |
| $color-scrollList_footer-border | var(--semi-color-border) | 滚动列表底部描边颜色 |
| $height-scrollList | 300px | |
| $height-scrollList_item | 36px | |
| $width-scrollList_item-border | $border-thickness-control | |
| $width-scrollList_item_sel_svg | 16px | |
| $width-scrollList_item_wheel_selector-border | $border-thickness-control | |
| $height-scrollList_line | 1px | |
| $width-scrollList_footer-border | $border-thickness-control | |
| $spacing-scrollList_header-paddingY | 0 | |
| $spacing-scrollList_header-paddingX | 16px | |
| $spacing-scrollList_header_title-paddingY | $spacing-base | |
| $spacing-scrollList_header_title-paddingX | 0 | |
| $spacing-scrollList_body-paddingY | 0 | |
| $spacing-scrollList_body-paddingX | 16px | |
| $spacing-scrollList_item_ul-padding | 0 | |
| $spacing-scrollList_item_ul-margin | 0 | |
| $spacing-scrollList_item_ul-paddingBottom | ($height-scrollList - $height-scrollList_item) * 0.5 | |
| $spacing-scrollList_item_sel_svg-marginRight | 12px | |
| $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-padding | 10px | |
| $radius-scrollList | var(--semi-border-radius-medium) | |
| $font-scrollList_header_title-fontWeight | $font-weight-bold | |
| $font-scrollList_item_wheel_item_selected-fontWeight | $font-weight-bold | |
| $shadow-scrollList | var(--semi-shadow-elevated) |