Search code examples
reactjsreact-select

How to make React Select options menu start from specific index of options array


In React Select, I have a long options list like below and it makes so difficult to choose one of last options. The user has to scroll all options down to get the last option.

Is there a way to start options of select menu from middle of array list?

Like starting from options\[20\] and user can scroll down and up to get first or last options

I have an array of options like this:

const options = [
    {
        label : '04:45',
        value : '04:45'
    },
    {
        label : '05:00',
        value : '05:00'
    },
    {
        label : '05:15',
        value : '05:15'
    },
    {
        label : '05:30',
        value : '05:30'
    },
    {
        label : '05:45',
        value : '05:45'
    },
    {
        label : '06:00',
        value : '06:00'
    },
    {
        label : '06:15',
        value : '06:15'
    },
    {
        label : '06:30',
        value : '06:30'
    },
    {
        label : '06:45',
        value : '06:45'
    },
    {
        label : '07:00',
        value : '07:00'
    },
    {
        label : '07:15',
        value : '07:15'
    },
]

and using React Select

<Select 
    isRtl
    options={hours}
    unstyled
    isSearchable={false}
/>

I tried defaultValue for that but it's not behaving like I'm expecting.


Solution

  • Select the middle option by default and use a custom option component. When an option is selected, call scrollIntoView({ behavior: "instant", block: "center" }).

    const hours = [
        {
            label: '04:45',
            value: '04:45'
        },
        {
            label: '05:00',
            value: '05:00'
        },
        {
            label: '05:15',
            value: '05:15'
        },
        {
            label: '05:30',
            value: '05:30'
        },
        {
            label: '05:45',
            value: '05:45'
        },
        {
            label: '06:00',
            value: '06:00'
        },
        {
            label: '06:15',
            value: '06:15'
        },
        {
            label: '06:30',
            value: '06:30'
        },
        {
            label: '06:45',
            value: '06:45'
        },
        {
            label: '07:00',
            value: '07:00'
        },
        {
            label: '07:15',
            value: '07:15'
        },
        {
            label: '07:30',
            value: '07:30'
        },
        {
            label: '07:45',
            value: '07:45'
        }
    ];
    
    const Option = (props) => {
        const ref = useRef();
    
        useEffect(() => {
            props.isSelected && ref.current.scrollIntoView({ behavior: "instant", block: "center" });
        }, [props.isSelected]);
    
        return !props.isDisabled ? (
            <components.Option {...props} innerRef={ref} />) : null;
    };
    
    export default function () {
        const components = {
            Option: Option,
        }
        return (
            <Select
                components={components}
                isRtl
                defaultValue={hours[Math.floor(hours.length/2)]}
                options={hours}
                isSearchable={false}
            />
        )
    }
    

    Edit:

    If you don't want any default option selected, you can still use the same logic but only scroll the middle option into the center when nothing is selected. (props.getValue() returns the selected options.)

    const CustomOption = (props) => {
        const ref = useRef();
        useEffect(() => {
            if (props.getValue().length > 0 && props.value === props.getValue()[0].value) {
                // uncomment below if you want the first selected option in the center too
                // ref.current.scrollIntoView({ behavior: "instant", block: "center" });
            }else if(props.getValue().length == 0 && props.value === hours[Math.floor(hours.length / 2)].value){
                ref.current.scrollIntoView({ behavior: "instant", block: "center" })
            }
        }, []);
    
        return !props.isDisabled ? (
            <components.Option {...props} innerRef={ref} />) : null;
    }