MDX (Markdown for JSX) предоставляет гибкость работы с контентом, позволяя интегрировать React-компоненты прямо в Markdown. Одной из ключевых возможностей современных интерфейсов является темизация, которая позволяет адаптировать визуальное оформление под светлую, тёмную или кастомные темы. MDX не содержит встроенной системы темизации, поэтому её реализация обычно строится на сочетании React-контекста, CSS-in-JS и динамического выбора стилей.
Первым шагом является создание контекста темы. Контекст позволяет передавать текущую тему во все компоненты MDX без необходимости пробрасывать пропсы вручную.
import React, { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prev) => (prev === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = () => useContext(ThemeContext);
Ключевые моменты:
ThemeContext предоставляет глобальное состояние
темы.toggleTheme позволяет динамически переключать
темы.useTheme упрощает доступ к текущей теме в компонентах
MDX.MDX-компоненты могут менять стили в зависимости от текущей темы. Для
этого часто используют CSS-in-JS библиотеки, такие как
styled-components или @emotion/react.
Пример с styled-components:
import styled from 'styled-components';
import { useTheme } from './ThemeProvider';
const ThemedButton = styled.button`
background-color: ${({ theme }) => (theme === 'light' ? '#fff' : '#333')};
color: ${({ theme }) => (theme === 'light' ? '#000' : '#fff')};
border: 1px solid ${({ theme }) => (theme === 'light' ? '#ccc' : '#555')};
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
`;
export const Button = () => {
const { theme, toggleTheme } = useTheme();
return <ThemedButton theme={theme} onCl ick={toggleTheme}>Сменить тему</ThemedButton>;
};
Особенности подхода:
theme.MDX позволяет использовать React-компоненты внутри Markdown. Это позволяет добавлять тематизированные элементы прямо в контент:
# Пример тематизированной кнопки
<Button />
При рендеринге компонента Button будет автоматически
применяться текущая тема из контекста. Это означает, что одна и та же
MDX-страница может корректно отображаться в светлой и тёмной
теме, без необходимости дублировать контент.
Для более масштабной темизации важно учитывать глобальные CSS-переменные. С их помощью можно менять цвета всего интерфейса в зависимости от темы:
import { createGlobalStyle } from 'styled-components';
import { useTheme } from './ThemeProvider';
const GlobalStyle = createGlobalStyle`
body {
background-color: ${({ theme }) => (theme === 'light' ? '#f9f9f9' : '#121212')};
color: ${({ theme }) => (theme === 'light' ? '#000' : '#fff')};
transition: background-color 0.3s, color 0.3s;
}
`;
export const ThemedLayout = ({ children }) => {
const { theme } = useTheme();
return (
<>
<GlobalStyle theme={theme} />
{children}
</>
);
};
Важные моменты:
transition обеспечивает плавное переключение темы.MDXProvider позволяет замещать стандартные
элементы Markdown на кастомные React-компоненты, поддерживающие
тему:
import { MDXProvider } from '@mdx-js/react';
import { ThemedHeading, ThemedParagraph } from './ThemedComponents';
const components = {
h1: ThemedHeading,
p: ThemedParagraph,
};
export const ThemedMDX = ({ children }) => {
return <MDXProvider components={components}>{children}</MDXProvider>;
};
Преимущества:
Можно определить несколько кастомных тем и переключаться между ними динамически:
const themes = {
light: { background: '#fff', text: '#000', accent: '#0070f3' },
dark: { background: '#121212', text: '#fff', accent: '#1db954' },
solarized: { background: '#fdf6e3', text: '#657b83', accent: '#b58900' },
};
export const ThemeProvider = ({ children }) => {
const [themeName, setThemeName] = useState('light');
const toggleTheme = (newTheme) => setThemeName(newTheme);
const theme = themes[themeName];
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
Такой подход позволяет создавать разнообразные визуальные схемы для MDX-контента, включая корпоративные или брендированные темы.
Для полной темизации MDX-проекта обычно используется следующая архитектура:
Этот подход обеспечивает гибкую, масштабируемую и легко поддерживаемую систему темизации для любых MDX-документов, включая документацию, блоги и интерактивные руководства.