Кастомизация выпадающих списков

В библиотеке MUI (Material-UI) выпадающие списки реализуются с помощью компонентов Select, MenuItem и вспомогательных элементов, таких как FormControl и InputLabel. Эти компоненты предоставляют базовую функциональность, но для создания уникального интерфейса требуется кастомизация внешнего вида, поведения и взаимодействия с пользователем.

Структура базового Select

import * as React from 'react';
import { FormControl, InputLabel, Select, MenuItem } from '@mui/material';

function BasicSelect() {
  const [value, setValue] = React.useState('');

  const handleChange = (event) => {
    setValue(event.target.value);
  };

  return (
    <FormControl fullWidth>
      <InputLabel id="demo-select-label">Выберите опцию</InputLabel>
      <Sel ect
        labelId="demo-select-label"
        value={value}
        onCha nge={handleChange}
      >
        <MenuItem value={10}>Десять</MenuItem>
        <MenuItem value={20}>Двадцать</MenuItem>
        <MenuItem value={30}>Тридцать</MenuItem>
      </Select>
    </FormControl>
  );
}

Эта структура представляет стандартный выпадающий список с поддержкой состояния выбранного значения и простой интеграцией с формами. Для более сложного интерфейса необходимо использовать кастомизацию через стили и компоненты MUI.


Стилизация через sx и styled

MUI предоставляет два основных способа изменения внешнего вида компонентов: через проп sx и через API styled.

Использование sx

<Sel ect
  sx={{
    backgroundColor: '#f0f0f0',
    borderRadius: 2,
    '& .MuiSelect-icon': {
      color: 'red',
    },
  }}
>
  • backgroundColor изменяет фон селекта.
  • borderRadius задаёт скругление.
  • Селектор & .MuiSelect-icon позволяет менять цвет и размер стрелки.

Использование styled

import { styled } fr om '@mui/material/styles';
import Sel ect fr om '@mui/material/Sel ect';

const CustomSelect = styled(Select)(({ theme }) => ({
  backgroundColor: theme.palette.background.paper,
  border: `1px solid ${theme.palette.divider}`,
  '&:hover': {
    borderColor: theme.palette.primary.main,
  },
  '& .MuiSelect-icon': {
    color: theme.palette.secondary.main,
  },
}));

styled позволяет создавать переиспользуемые компоненты с комплексными стилями, включая состояния hover, focus и кастомные вложенные элементы.


Кастомизация MenuItem

MenuItem отвечает за элементы списка. Часто требуется добавить иконки, группировать элементы или изменять их поведение при наведении.

<MenuItem value={10} sx={{ display: 'flex', alignItems: 'center' }}>
  <img src="/icons/icon10.svg" alt="" width={20} style={{ marginRight: 8 }} />
  Десять
</MenuItem>
  • Использование display: flex позволяет расположить иконку и текст горизонтально.
  • Отступ marginRight создаёт визуальную гармонию между элементами.

Можно создавать группированные элементы с помощью ListSubheader:

import { ListSubheader } fr om '@mui/material';

<Sel ect value={value} onCha nge={handleChange}>
  <ListSubheader>Группа 1</ListSubheader>
  <MenuItem value={10}>Десять</MenuItem>
  <MenuItem value={20}>Двадцать</MenuItem>
  <ListSubheader>Группа 2</ListSubheader>
  <MenuItem value={30}>Тридцать</MenuItem>
</Select>

Кастомное поведение с renderValue и MenuProps

Проп renderValue позволяет отображать выбранное значение нестандартным образом:

<Select
  value={value}
  onCha nge={handleChange}
  renderValue={(selected) => `Выбрано: ${selected}`}
>

Для управления поведением выпадающего списка используется MenuProps:

<Select
  value={value}
  onCha nge={handleChange}
  MenuProps={{
    PaperProps: {
      style: {
        maxHeight: 200,
        width: 250,
      },
    },
    anchorOrigin: {
      vertical: 'bottom',
      horizontal: 'left',
    },
    transformOrigin: {
      vertical: 'top',
      horizontal: 'left',
    },
  }}
>
  • PaperProps задаёт размеры и стили контейнера выпадающего меню.
  • anchorOrigin и transformOrigin управляют позицией всплывающего списка относительно селекта.

Интеграция с автокомплитом и асинхронными данными

Для динамических списков рекомендуется использовать компонент Autocomplete, который построен поверх Select и поддерживает асинхронную подгрузку данных:

import { Autocomplete, TextField } fr om '@mui/material';

<Autocomplete
  options={options} // массив объектов или строк
  getOptionLabel={(option) => option.label}
  renderInput={(params) => <TextField {...params} label="Поиск" />}
  onCha nge={(event, value) => console.log(value)}
/>
  • getOptionLabel позволяет контролировать отображаемый текст.
  • Асинхронная подгрузка реализуется через динамическое обновление массива options по мере ввода.

Анимации и кастомные иконки

MUI поддерживает добавление кастомных иконок для открытия/закрытия меню и анимаций элементов. Например, с помощью IconComponent можно заменить стандартную стрелку:

import ArrowDropDownIcon fr om '@mui/icons-material/ArrowDropDown';

<Select
  value={value}
  onCha nge={handleChange}
  IconComponent={ArrowDropDownIcon}
>

Для анимации элементов меню применяются CSS-переходы через sx или styled, либо библиотека framer-motion для сложных анимаций появления и исчезновения элементов.


Заключение по кастомизации

MUI предоставляет гибкий и мощный инструмент для создания уникальных выпадающих списков. Комбинация:

  • sx и styled для визуального оформления,
  • renderValue и MenuProps для контроля поведения,
  • кастомных компонентов и иконок для визуальных особенностей,
  • интеграции с Autocomplete для динамических списков

позволяет реализовать как простые формы, так и сложные интерфейсы с уникальным пользовательским опытом.