Кастомные иконки

MUI предоставляет встроенную поддержку иконок через библиотеку @mui/icons-material, однако в реальных проектах часто возникает необходимость использовать свои, кастомные SVG-иконки. Для этого MUI предлагает гибкие инструменты, позволяющие интегрировать иконки без потери совместимости с компонентами библиотеки, такими как Button, IconButton или ListItemIcon.


Импорт и настройка кастомной SVG-иконки

Самый простой способ добавить кастомную иконку — использовать компонент SvgIcon из @mui/material. Этот компонент позволяет обернуть SVG-контент и преобразовать его в полноценный компонент MUI.

import SvgIcon from '@mui/material/SvgIcon';

function HomeIcon(props) {
  return (
    <SvgIcon {...props}>
      <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
    </SvgIcon>
  );
}

Ключевые моменты:

  • Атрибут viewBox из исходного SVG автоматически подхватывается SvgIcon, но его можно переопределить при необходимости.
  • Все пропсы props, переданные компоненту, автоматически поддерживают стилизацию через sx или стандартные свойства MUI (color, fontSize).
  • Использование SvgIcon позволяет сохранять совместимость с компонентами MUI, например:
import IconButton from '@mui/material/IconButton';

<IconButton color="primary">
  <HomeIcon fontSize="large" />
</IconButton>

Стилизация кастомных иконок

MUI предоставляет несколько способов управлять стилями кастомных иконок:

  1. Через проп color: SvgIcon поддерживает стандартные цвета MUI: primary, secondary, action, error, disabled, inherit.
<HomeIcon color="secondary" />
  1. Через проп fontSize: Можно использовать предустановленные размеры: small, medium, large, или указать кастомный размер через sx.
<HomeIcon fontSize="small" />
<HomeIcon sx={{ fontSize: 48 }} />
  1. Через sx для полной кастомизации: Позволяет задавать любые CSS-свойства:
<HomeIcon sx={{ color: 'green', transform: 'rotate(45deg)' }} />

Создание библиотеки кастомных иконок

Для удобства лучше вынести все кастомные иконки в отдельный модуль, например icons.js:

import SvgIcon from '@mui/material/SvgIcon';

export function HomeIcon(props) {
  return (
    <SvgIcon {...props}>
      <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
    </SvgIcon>
  );
}

export function SettingsIcon(props) {
  return (
    <SvgIcon {...props}>
      <path d="M19.43 12.98l1.77-1.03-1-1.73-1.77 1.03a6.947 6.947 0 0 0-1.69-0.98l-0.27-1.92h-2l-0.27 1.92c-0.62 0.21-1.2 0.52-1.69 0.98L5.8 10.22l-1 1.73 1.77 1.03c-0.05 0.33-0.08 0.66-0.08 1s0.03 0.67 0.08 1l-1.77 1.03 1 1.73 1.77-1.03c0.49 0.46 1.07 0.77 1.69 0.98l0.27 1.92h2l0.27-1.92c0.62-0.21 1.2-0.52 1.69-0.98l1.77 1.03 1-1.73-1.77-1.03c0.05-0.33 0.08-0.66 0.08-1s-0.03-0.67-0.08-1z"/>
    </SvgIcon>
  );
}

Теперь их легко импортировать в любом компоненте:

import { HomeIcon, SettingsIcon } from './icons';

<HomeIcon color="primary" />
<SettingsIcon sx={{ fontSize: 36, color: 'red' }} />

Интеграция кастомных иконок с MUI Button и List

Кастомные иконки полностью совместимы с компонентами, которые ожидают иконку:

import Button from '@mui/material/Button';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';

<Button startIcon={<HomeIcon />}>Главная</Button>

<List>
  <ListItem>
    <ListItemIcon>
      <SettingsIcon />
    </ListItemIcon>
    <ListItemText primary="Настройки" />
  </ListItem>
</List>

Это позволяет создать единый визуальный стиль приложения, не ограничиваясь библиотечными иконками.


Использование кастомных SVG-файлов

Если SVG уже хранится как отдельный файл, его можно импортировать с помощью @svgr/webpack (часто настроено по умолчанию в Create React App) или обернуть вручную:

import { ReactComponent as LogoSVG } from './logo.svg';
import SvgIcon from '@mui/material/SvgIcon';

function LogoIcon(props) {
  return (
    <SvgIcon component={LogoSVG} viewBox="0 0 100 100" {...props} />
  );
}

Преимущества такого подхода:

  • Нет необходимости редактировать содержимое SVG вручную.
  • Полная интеграция с MUI color, fontSize и sx.

Советы по производительности и организации

  • Минимизировать SVG перед использованием (например, с помощью svgo) для уменьшения размера бандла.
  • Создавать отдельный файл с набором иконок, чтобы легко масштабировать проект.
  • Использовать memo для часто используемых иконок, чтобы избежать лишних перерендеров:
import { memo } from 'react';

const HomeIconMemo = memo(HomeIcon);
  • Соблюдать единый стиль: одна высота и ширина для всех иконок в одной категории помогает визуальной консистентности интерфейса.

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