Почему не применяются стили кастомного варианта кнопки MUI
Решение проблем с кастомными вариантами кнопок в Material-UI. Узнайте, почему стили вашего варианта 'iconary' не работают и как это исправить.
Почему не применяются стили кастомного варианта кнопки MUI iconary?
Я создал кастомную кнопку, расширив интерфейс ButtonPropsVariantOverrides, но стили для variant='iconary' не работают. Вот моя конфигурация:
import "@mui/material/Button";
declare module "@mui/material/Button" {
interface ButtonPropsVariantOverrides {
iconary: true;
}
}
MuiButton: {
variants: [
{
props: { variant: 'iconary' },
style: {
width: 32,
height: 32,
minWidth: "none",
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '5px'
}
},
],
styleOverrides: {
root: {
textTransform: "none",
fontWeight: 400,
fontSize: 16,
},
contained: { borderRadius: "10px" },
sizeMedium: { padding: "8px 32px" },
sizeLarge: { padding: "12px inherit" },
},
}
Применяю кнопку так:
<Button
onClick={() => setIsChangeNameModalOpened(true)}
variant="iconary"
sx={{ backgroundColor: "primary.light" }}
>
<EditOutlined fontSize="small" sx={{ color: "primary.main", width: 16, height: 16 }} />
</Button>;
Ошибок нет, но стили variant='iconary' не применяются. В чем может быть проблема?
Когда вы определяете кастомный вариант кнопки через ButtonPropsVariantOverrides, но стили не применяются, это обычно связано с несколькими распространенными проблемами. Наиболее вероятные причины — неправильная структура темы, отсутствие ThemeProvider или конфликт с другими стилями.
Содержание
- Основные причины не применяемых стилей
- Правильная структура темы для кастомных вариантов
- Проверка на наличие ThemeProvider
- Конфликты со стилями
- Полный рабочий пример
- Проверка в режиме разработки
- Дополнительные методы стилизации
Основные причины не применяемых стилей
Наиболее частые причины, почему ваш кастомный вариант iconary не работает:
- Неправильная структура темы: Ваша конфигурация должна быть внутри
createTheme, а не просто в объектеMuiButton. - Отсутствие ThemeProvider: Без ThemeProvider стили темы не будут применены.
- Конфликты со
styleOverrides: Ваши стилиstyleOverridesмогут перекрывать кастомные варианты. - Неправильное объявление модуля: Хотя вы объявили
iconary: true, убедитесь, что это сделано правильно.
Правильная структура темы для кастомных вариантов
Ваша основная проблема — в том, как вы структурировали тему. Кастомные варианты должны быть определены внутри createTheme:
import { createTheme, ThemeProvider } from '@mui/material/styles';
// Объявление кастомного варианта
declare module "@mui/material/Button" {
interface ButtonPropsVariantOverrides {
iconary: true;
}
}
// Правильная структура темы
const theme = createTheme({
components: {
MuiButton: {
variants: [
{
props: { variant: 'iconary' },
style: {
width: 32,
height: 32,
minWidth: "none",
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '5px'
}
},
],
styleOverrides: {
root: {
textTransform: "none",
fontWeight: 400,
fontSize: 16,
},
contained: { borderRadius: "10px" },
sizeMedium: { padding: "8px 32px" },
sizeLarge: { padding: "12px inherit" },
},
},
},
});
// Обертка приложения в ThemeProvider
function App() {
return (
<ThemeProvider theme={theme}>
<YourComponent />
</ThemeProvider>
);
}
Проверка на наличие ThemeProvider
Убедитесь, что ваш компонент обернут в ThemeProvider. Без этого стили кастомных вариантов не будут применены:
import { ThemeProvider } from '@mui/material/styles';
function YourComponent() {
return (
<ThemeProvider theme={theme}>
<Button
onClick={() => setIsChangeNameModalOpened(true)}
variant="iconary"
sx={{ backgroundColor: "primary.light" }}
>
<EditOutlined fontSize="small" sx={{ color: "primary.main", width: 16, height: 16 }} />
</Button>
</ThemeProvider>
);
}
Конфликты со стилями
Ваша конфигурация может иметь конфликты между variants и styleOverrides. В Material‑UI версии 5+ структурирование стало более строгим. Попробуйте разделить стили:
const theme = createTheme({
components: {
MuiButton: {
// Кастомные варианты
variants: [
{
props: { variant: 'iconary' },
style: {
width: 32,
height: 32,
minWidth: "none",
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '5px'
}
},
],
// Глобальные переопределения
styleOverrides: {
root: {
textTransform: "none",
fontWeight: 400,
fontSize: 16,
},
contained: {
'&.iconary': { // Добавьте селектор для конкретного варианта
borderRadius: "10px"
}
},
sizeMedium: {
'&.iconary': {
padding: "8px 32px"
}
},
sizeLarge: {
'&.iconary': {
padding: "12px inherit"
}
},
},
},
},
});
Полный рабочий пример
Вот полный рабочий пример, который должен работать без проблем:
// src/theme.ts
import { createTheme } from '@mui/material/styles';
// Объявление кастомного варианта
declare module "@mui/material/Button" {
interface ButtonPropsVariantOverrides {
iconary: true;
}
}
export const theme = createTheme({
components: {
MuiButton: {
variants: [
{
props: { variant: 'iconary' },
style: {
width: 32,
height: 32,
minWidth: "none",
padding: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '5px',
'&:hover': {
backgroundColor: 'rgba(0, 0, 0, 0.04)',
},
}
},
],
styleOverrides: {
root: {
textTransform: "none",
fontWeight: 400,
fontSize: 16,
},
contained: {
boxShadow: 'none',
'&:hover': {
boxShadow: 'none',
},
},
},
},
},
});
// src/App.tsx
import { ThemeProvider } from '@mui/material/styles';
import { Button } from '@mui/material';
import { EditOutlined } from '@ant-design/icons';
import { theme } from './theme';
function App() {
return (
<ThemeProvider theme={theme}>
<Button
variant="iconary"
sx={{ backgroundColor: "primary.light" }}
>
<EditOutlined fontSize="small" sx={{ color: "primary.main", width: 16, height: 16 }} />
</Button>
</ThemeProvider>
);
}
Проверка в режиме разработки
Если стили все еще не применяются, выполните следующие проверки:
- Проверьте консоль: Включите режим строгого режима разработки Material‑UI, чтобы увидеть предупреждения.
- Проверьте DOM: В инспекторе браузера посмотрите, какие классы применяются к кнопке.
- Проверьте приоритет стилей: Убедитесь, что другие стили не переопределяют ваши.
Для включения режима отладки:
import { createTheme, Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';
const theme = createTheme({
// ваша конфигурация
});
// Используйте CssVarsProvider вместо ThemeProvider для отладки
<CssVarsProvider theme={theme}>
{/* ваши компоненты */}
</CssVarsProvider>
Дополнительные методы стилизации
Если кастомный вариант все еще не работает, попробуйте альтернативные методы:
1. Использование sx prop вместо variants
<Button
onClick={() => setIsChangeNameModalOpened(true)}
sx={{
width: 32,
height: 32,
minWidth: "none",
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '5px',
backgroundColor: "primary.light",
}}
>
<EditOutlined fontSize="small" sx={{ color: "primary.main", width: 16, height: 16 }} />
</Button>
2. Создание кастомного компонента
import { Button } from '@mui/material';
const IconaryButton = ({ children, ...props }) => (
<Button
{...props}
sx={{
width: 32,
height: 32,
minWidth: "none",
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '5px',
...props.sx,
}}
>
{children}
</Button>
);
// Использование
<IconaryButton onClick={() => setIsChangeNameModalOpened(true)} variant="contained" sx={{ backgroundColor: "primary.light" }}>
<EditOutlined fontSize="small" sx={{ color: "primary.main", width: 16, height: 16 }} />
</IconaryButton>
3. Использование styled API
import styled from '@mui/material/styles/styled';
import { Button } from '@mui/material';
const IconaryButton = styled(Button)(({ theme }) => ({
width: 32,
height: 32,
minWidth: "none",
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: '5px',
}));
// Использование
<IconaryButton
onClick={() => setIsChangeNameModalOpened(true)}
variant="contained"
sx={{ backgroundColor: "primary.light" }}
>
<EditOutlined fontSize="small" sx={{ color: "primary.main", width: 16, height: 16 }} />
</IconaryButton>
Чаще всего проблема решается правильной структурой темы и оберткой в ThemeProvider. Если после всех проверок стиль все равно не применяется, попробуйте временно удалить styleOverrides или использовать один из альтернативных методов стилизации.
Источники
- Themed components - Material UI Documentation
- Creating custom variants with Material UI - Stack Overflow
- How to use Material UI custom variants in React with Typescript - Stack Overflow
- Material-UI Button custom variant not working - GitHub Issues
- Material-UI TypeScript theme customization - Softbinator Blog
Заключение
- Основная проблема: Стили кастомного варианта не применяются из-за неправильной структуры темы или отсутствия ThemeProvider.
- Решение: Оберните ваше приложение в ThemeProvider с правильно настроенной темой, где кастомные варианты определены в
components.MuiButton.variants. - Альтернативы: Если вариант не работает, используйте
sxprop для стилизации или создайте кастомный компонент. - Проверка: Всегда проверяйте консоль на наличие сообщений об ошибках и inspect DOM для просмотра примененных стилей.
- TypeScript: Убедитесь, что объявление
ButtonPropsVariantOverridesкорректно и находится в правильном месте.