Styles API
Styles API
Styles API란 무엇인가요
Styles API는 Mantine 컴포넌트 안의 어떤 요소든 인라인 또는 theme 객체로 스타일을 커스터마이즈할 수 있게 해주는 props와 기법의 집합이에요. 스타일이 있는 모든 Mantine 컴포넌트는 Styles API를 지원해요.
출처: 문서
본문
Styles API selectors
Styles API를 지원하는 모든 Mantine 컴포넌트는 컴포넌트 내부의 요소에 스타일을 적용하는 데 사용할 수 있는 요소 이름 집합을 가지고 있어요. 간단히 하기 위해 Mantine 문서에서는 이 요소 이름들을 selector라고 불러요. selector 정보는 컴포넌트 문서의 Styles API 탭에서 찾을 수 있어요.
Button 컴포넌트 selector 예시:
| Selector | 정적 selector | 설명 |
|---|---|---|
| root | .mantine-Button-root | 루트 요소 |
| loader | .mantine-Button-loader | Loader 컴포넌트, loading prop이 설정될 때만 표시돼요 |
| inner | .mantine-Button-inner | 다른 모든 요소를 포함하며 root 요소의 자식이에요 |
| section | .mantine-Button-section | 버튼의 왼쪽/오른쪽 section |
| label | .mantine-Button-label | 버튼 children |
컴포넌트 props와 theme.components 양쪽에서 classNames와 styles에 이 selector들을 사용할 수 있어요:
import { Button, createTheme, MantineProvider } from '@mantine/core';
function ClassNamesDemo() {
return <Button classNames={{ root: 'my-root-class' }}>Button</Button>;
}
function StylesDemo() {
return <Button styles={{ root: { backgroundColor: 'red' } }}>Button</Button>;
}
const theme = createTheme({
components: {
Button: Button.extend({
classNames: {
root: 'my-root-class',
label: 'my-label-class',
inner: 'my-inner-class',
},
styles: {
root: { backgroundColor: 'red' },
label: { color: 'blue' },
inner: { fontSize: 20 },
},
}),
},
});
function ProviderDemo() {
return (
<MantineProvider theme={theme}>
<Button>Button</Button>
</MantineProvider>
);
}
classNames prop
classNames prop으로 Mantine 컴포넌트의 내부 요소에 클래스를 추가할 수 있어요. 요소 이름을 키로, 클래스를 값으로 가지는 객체를 받아요:
import { useState } from 'react';
import { TextInput } from '@mantine/core';
import classes from './Demo.module.css';
function Demo() {
const [value, setValue] = useState('');
const [focused, setFocused] = useState(false);
const floating = focused || value.length > 0 || undefined;
return (
<TextInput
label="Floating label input"
classNames={{ label: classes.label, input: classes.input }}
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
value={value}
onChange={(event) => setValue(event.currentTarget.value)}
/>
);
}
theme.components의 classNames
특정 유형의 모든 컴포넌트에 적용하려면 theme.components에서도 classNames를 정의할 수 있어요:
import { useState } from 'react';
import {
createTheme,
MantineProvider,
TextInput,
} from '@mantine/core';
// Styles are the same as in previous example
import classes from './Demo.module.css';
const theme = createTheme({
components: {
TextInput: TextInput.extend({
classNames: {
root: classes.root,
input: classes.input,
label: classes.label,
},
}),
},
});
function Demo() {
return (
<MantineProvider theme={theme}>
{/* Your app here */}
</MantineProvider>
);
}
컴포넌트 CSS variables
대부분의 Mantine 컴포넌트는 색상, 크기, padding 및 다른 속성을 정의하기 위해 CSS variables를 사용해요. theme.components의 커스텀 CSS variables resolver 함수로 이 값들을 재정의하거나 vars prop으로 전달할 수 있어요.
CSS variables 정보는 컴포넌트 문서의 Styles API 탭에서 찾을 수 있어요. Button 컴포넌트 CSS variables 예시:
| Selector | 변수 | 설명 |
|---|---|---|
| root | --button-bg | background를 제어해요 |
| --button-bd | border를 제어해요 |
|
| --button-hover | hover 시 background를 제어해요 |
|
| --button-color | 텍스트 color를 제어해요 |
|
| --button-hover-color | hover 시 텍스트 color를 제어해요 |
|
| --button-radius | border-radius를 제어해요 |
|
| --button-height | 버튼의 height를 제어해요 |
|
| --button-padding-x | 버튼의 가로 padding을 제어해요 |
|
| --button-fz | 버튼의 font-size를 제어해요 |
|
| --button-justify | inner 요소의 justify-content를 제어해요 |
Button 컴포넌트에 더 많은 크기를 추가하는 데 사용하는 커스텀 CSS variables resolver 함수 예시:
import { Button, Group, MantineProvider, createTheme } from '@mantine/core';
const theme = createTheme({
components: {
Button: Button.extend({
vars: (theme, props) => {
if (props.size === 'xxl') {
return {
root: {
'--button-height': '60px',
'--button-padding-x': '30px',
'--button-fz': '24px',
},
};
}
if (props.size === 'xxs') {
return {
root: {
'--button-height': '24px',
'--button-padding-x': '10px',
'--button-fz': '10px',
},
};
}
return { root: {} };
},
}),
},
});
function Demo() {
return (
<MantineProvider theme={theme}>
<Group>
<Button size="xxl">XXL Button</Button>
<Button size="xxs">XXS Button</Button>
</Group>
</MantineProvider>
);
}
styles prop
styles prop은 classNames와 같은 방식으로 동작하지만 인라인 스타일을 적용해요. 인라인 스타일은 클래스보다 특이성(specificity)이 높으므로 !important를 사용하지 않고는 클래스로 재정의할 수 없다는 점에 주의하세요. styles prop 안에서는 pseudo-classes(예: :hover, :first-of-type)와 미디어 쿼리를 사용할 수 없어요.
import { Button } from '@mantine/core';
function Demo() {
const gradient =
'linear-gradient(45deg, var(--mantine-color-pink-filled) 0%, var(--mantine-color-orange-filled) 50%, var(--mantine-color-yellow-filled) 100%)';
return (
<Button
styles={{
root: {
backgroundImage: gradient,
},
}}
>
Gradient button
</Button>
);
}
styles prop 사용
문서의 일부 예시와 데모는 편의를 위해 styles prop을 사용하지만, classNames prop이 더 유연하고 성능도 더 좋으므로 styles prop을 컴포넌트 스타일링의 주요 수단으로 쓰는 것은 권장되지 않아요.
컴포넌트 props에 기반한 Styles API
classNames와 styles에 콜백 함수를 전달할 수도 있어요. 이 함수는 첫 번째 인자로 theme, 두 번째로 컴포넌트 props를 받아요. 클래스 객체(classNames용) 또는 styles 객체(styles용)를 반환해야 해요.
이 기능을 사용하면 컴포넌트 props에 따라 스타일을 조건부로 적용할 수 있어요. 예를 들어 input이 required이면 TextInput label 색상을 바꾸거나, input이 틀리면 배경색을 바꿀 수 있어요:
import cx from 'clsx';
import { MantineProvider, createTheme, TextInput } from '@mantine/core';
import classes from './Demo.module.css';
const theme = createTheme({
components: {
TextInput: TextInput.extend({
classNames: (_theme, props) => ({
label: cx({ [classes.labelRequired]: props.required }),
input: cx({ [classes.inputError]: props.error }),
}),
}),
},
});
function Demo() {
return (
<MantineProvider theme={theme}>
<TextInput label="Required input" required />
<TextInput label="Input with error" error />
</MantineProvider>
);
}
정적 클래스
Styles API를 지원하는 모든 컴포넌트에는 classNames나 styles props 없이 컴포넌트에 스타일을 적용할 수 있는 정적 클래스도 포함돼 있어요. 기본적으로 정적 클래스는 .mantine-{ComponentName}-{selector} 형식이에요. 예를 들어 Button 컴포넌트의 root selector는 .mantine-Button-root 클래스를 가져요.
정적 클래스를 사용해 CSS나 다른 어떤 스타일링 솔루션으로 컴포넌트에 스타일을 적용할 수 있어요:
.mantine-Button-root {
background-color: red;
}
정적 클래스의 접두사는 MantineProvider의 classNamesPrefix로 바꿀 수 있어요.
컴포넌트 클래스
각 컴포넌트의 클래스는 Component.classes 객체에서 사용할 수 있어요. 예를 들어 Button의 클래스는 Button.classes에서 찾을 수 있어요:
| Key | Class |
|---|---|
| root | m_77c9d27d |
| inner | m_80f1301b |
| label | m_811560b9 |
| section | m_a74036a |
| loader | m_a25b86ee |
| group | m_80d6d844 |
| groupSection | m_70be2a01 |
이 클래스들을 사용해 Mantine 컴포넌트와 동일한 스타일을 가진 컴포넌트를 만들 수 있어요:
import { Button } from '@mantine/core';
function Demo() {
return <div className={Button.classes.root}>Custom button</div>;
}
Attributes
attributes prop을 사용해 Mantine 컴포넌트의 내부 요소에 속성을 전달할 수 있어요. 예를 들어 테스트 목적으로 data 속성을 추가하는 데 사용할 수 있어요:
import { Button } from '@mantine/core';
function Demo() {
return (
<Button attributes={{ root: { 'data-test': 'button' } }}>
Button
</Button>
);
}