Theme 객체

Theme 객체

Mantine theme은 애플리케이션의 색상, 폰트, spacing, border-radius 및 기타 디자인 토큰이 저장되는 객체예요.

interface MantineTheme {
  /** Controls focus ring styles. Supports the following options:
   *  - `auto` – focus ring is displayed only when the user navigates with keyboard (default value)
   *  - `always` – focus ring is displayed when the user navigates with keyboard and mouse
   *  - `never` – focus ring is always hidden (not recommended)
   */
  focusRing: 'auto' | 'always' | 'never';

  /** rem units scale; change if you customize font-size of <html> element
   *  default value is `1` (for `100%`/`16px` font-size on <html>)
   */
  scale: number;

  /** Determines whether `font-smoothing` property should be set on the body; `true` by default */
  fontSmoothing: boolean;

  /** White color */
  white: string;

  /** Black color */
  black: string;

  /** Object of colors; key is color name, value is an array of at least 10 strings (colors) */
  colors: MantineThemeColors;

  /** Index of theme.colors[color].
   *  Primary shade is used in all components to determine which color from theme.colors[color] should be used.
   *  Can be either a number (0–9) or an object to specify different color shades for light and dark color schemes.
   *  Default value `{ light: 6, dark: 8 }`
   *
   *  For example,
   *  { primaryShade: 6 } // shade 6 is used both for dark and light color schemes
   *  { primaryShade: { light: 6, dark: 7 } } // different shades for dark and light color schemes
   * */
  primaryShade: MantineColorShade | MantinePrimaryShade;

  /** Key of `theme.colors`; hex/rgb/hsl values are not supported.
   *  Determines which color will be used in all components by default.
   *  Default value – `blue`.
   * */
  primaryColor: string;

  /** Function to resolve colors based on variant.
   *  Can be used to deeply customize how colors are applied to `Button`, `ActionIcon`, `ThemeIcon`
   *  and other components that use colors from the theme.
   * */
  variantColorResolver: VariantColorsResolver;

  /** Determines whether text color must be changed based on the given `color` prop in filled variant
   *  For example, if you pass `color="blue.1"` to the Button component, text color will be changed to `var(--mantine-color-black)`
   *  Default value – `false`
   * */
  autoContrast: boolean;

  /** Determines which luminance value is used to determine if text color should be light or dark.
   *  Used only if `theme.autoContrast` is set to `true`.
   *  Default value is `0.3`
   * */
  luminanceThreshold: number;

  /** font-family used in all components; system fonts by default */
  fontFamily: string;

  /** Monospace font-family; used in code and other similar components, system fonts by default  */
  fontFamilyMonospace: string;

  /** Controls various styles of h1-h6 elements; used in Typography and Title components */
  headings: {
    fontFamily: string;
    fontWeight: string;
    textWrap: 'wrap' | 'nowrap' | 'balance' | 'pretty' | 'stable';
    sizes: {
      h1: HeadingStyle;
      h2: HeadingStyle;
      h3: HeadingStyle;
      h4: HeadingStyle;
      h5: HeadingStyle;
      h6: HeadingStyle;
    };
  };

  /** Object of values that are used to set `border-radius` in all components that support it */
  radius: MantineRadiusValues;

  /** Key of `theme.radius` or any valid CSS value. Default `border-radius` used by most components */
  defaultRadius: MantineRadius;

  /** Object of values that are used to set various CSS properties that control spacing between elements */
  spacing: MantineSpacingValues;

  /** Object of values that are used to control `font-size` property in all components */
  fontSizes: MantineFontSizesValues;

  /** Object of values that are used to control `line-height` property in `Text` component */
  lineHeights: MantineLineHeightValues;

  /** Object of values that are used to control `font-weight` property in components */
  fontWeights: MantineFontWeightsValues;

  /** Object of values that are used to control breakpoints in all components;
   *  values are expected to be defined in em
   * */
  breakpoints: MantineBreakpointsValues;

  /** Object of values that are used to add `box-shadow` styles to components that support `shadow` prop */
  shadows: MantineShadowsValues;

  /** Determines whether user OS settings to reduce motion should be respected; `false` by default */
  respectReducedMotion: boolean;

  /** Determines which cursor type will be used for interactive elements
   * - `default` – cursor that is used by native HTML elements, for example, `input[type="checkbox"]` has `cursor: default` styles
   * - `pointer` – sets `cursor: pointer` on interactive elements that do not have these styles by default
   */
  cursorType: 'default' | 'pointer';

  /** Default gradient configuration for components that support `variant="gradient"` */
  defaultGradient: MantineGradient;

  /** Class added to the elements that have active styles, for example, `Button` and `ActionIcon` */
  activeClassName: string;

  /** Class added to the elements that have focus styles, for example, `Button` or `ActionIcon`.
   *  Overrides `theme.focusRing` property.
   */
  focusClassName: string;

  /** Allows adding `classNames`, `styles` and `defaultProps` to any component */
  components: MantineThemeComponents;

  /** Any other properties that you want to access with the theme objects */
  other: MantineThemeOther;
}

출처: 문서

본문

사용법

theme을 커스터마이즈하려면 MantineProvider theme prop에 theme override 객체를 전달해요. theme override는 기본 theme과 깊게 병합돼요.

import { createTheme, MantineProvider } from '@mantine/core';

const theme = createTheme({
  colors: {
    // Add your color
    deepBlue: [
      '#eef3ff',
      '#dce4f5',
      '#b9c7e2',
      '#94a8d0',
      '#748dc1',
      '#5f7cb8',
      '#5474b4',
      '#44639f',
      '#39588f',
      '#2d4b81',
    ],
    // or replace default theme color
    blue: [
      '#eef3ff',
      '#dee2f2',
      '#bdc2de',
      '#98a0ca',
      '#7a84ba',
      '#6672b0',
      '#5c68ac',
      '#4c5897',
      '#424e88',
      '#364379',
    ],
  },

  shadows: {
    md: '1px 1px 3px rgba(0, 0, 0, .25)',
    xl: '5px 5px 3px rgba(0, 0, 0, .25)',
  },

  headings: {
    fontFamily: 'Roboto, sans-serif',
    sizes: {
      h1: { fontSize: '36px' },
    },
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      {/* Your app here */}
    </MantineProvider>
  );
}

Theme 속성

autoContrast

autoContrast는 주어진 color prop에 따라 텍스트 색상이 바뀌어야 하는지를 다음 컴포넌트에서 제어해요:

  • variant="filled"인 ActionIcon만

  • variant="filled"인 Alert만

  • variant="filled"인 Avatar만

  • variant="filled"인 Badge만

  • variant="filled"인 Button만

  • variant="filled"인 Chip만

  • variant="filled"인 NavLink만

  • variant="filled"인 ThemeIcon만

  • variant="filled"인 Checkbox만

  • variant="filled"인 Radio만

  • variant="pills"인 Tabs만

  • SegmentedControl

  • Stepper

  • Pagination

  • Progress

  • Indicator

  • Timeline

  • Spotlight

  • Calendar 컴포넌트를 기반으로 하는 모든 @mantine/dates 컴포넌트

autoContrast는 주어진 색상의 휘도(luminosity)가 luminanceThreshold 값보다 높은지 낮은지 확인하고 그에 따라 텍스트 색상을 theme.white 또는 theme.black으로 바꿔요.

autoContrast는 Spotlight와 @mantine/dates 컴포넌트를 제외하고 theme 수준에서 전역으로 또는 각 컴포넌트에 autoContrast prop으로 개별적으로 설정할 수 있어요. 이 컴포넌트들은 전역 theme 설정만 지원해요.

import { Button, Code, Group } from '@mantine/core';

function Demo() {
  return (
    <>
      <Group>
        <Code>autoContrast: true</Code>
        <Button color="lime.4">Lime.4 button</Button>
        <Button color="blue.2">Blue.2 button</Button>
        <Button color="orange.3">Orange.3 button</Button>
      </Group>
      <Group>
        <Code>autoContrast: false</Code>
        <Button color="lime.4" autoContrast={false}>Lime.4 button</Button>
        <Button color="blue.2" autoContrast={false}>Blue.2 button</Button>
        <Button color="orange.3" autoContrast={false}>Orange.3 button</Button>
      </Group>
    </>
  );
}

luminanceThreshold

luminanceThreshold는 텍스트 색상이 밝아야 할지 어두워야 할지 결정하는 데 어떤 휘도 값이 사용되는지 제어해요. theme.autoContrast가 true로 설정된 경우에만 사용돼요. 기본값은 0.3이에요.

import { Button, createTheme, MantineProvider, Stack } from '@mantine/core';

const theme = createTheme({
  autoContrast: true,
  luminanceThreshold: 0.3,
});

function Wrapper(props: any) {
  const buttons = Array(10)
    .fill(0)
    .map((_, index) => (
      <Button key={index} color={`red.${index}`}>Button</Button>
    ));

  return (
    <Stack>{buttons}</Stack>
  );
}

focusRing

theme.focusRing는 focus ring 스타일을 제어하며 다음 값을 지원해요:

  • auto(기본값 및 권장) – focus ring은 사용자가 키보드로 탐색할 때만 보여요. 이것은 네이티브 인터랙티브 요소의 기본 브라우저 동작이에요

  • always – focus ring은 사용자가 키보드와 마우스로 탐색할 때 보여요. 예를 들어 사용자가 버튼을 클릭할 때 focus ring이 보이고요

  • never – focus ring이 항상 숨겨져요; 권장되지 않아요 – 키보드로 탐색하는 사용자는 현재 포커스된 요소를 시각적으로 알 수 없게 돼요

focusClassName

theme.focusClassName은 Button이나 ActionIcon처럼 focus 스타일이 있는 요소에 추가되는 CSS 클래스예요. input을 제외한 모든 인터랙티브 컴포넌트의 focus ring 스타일을 커스터마이즈하는 데 사용할 수 있어요. theme.focusClassName이 설정되면 theme.focusRing은 무시된다는 점에 주의하세요.

import { MantineProvider, Button } from '@mantine/core';
import classes from './focus.module.css';

function Demo() {
  return (
    <MantineProvider theme={{ focusClassName: classes.focus }}>
      <Button>Click button to see custom focus ring</Button>
    </MantineProvider>
  );
}

:focus-visible selector

:focus-visible 선택자는 91% 이상의 브라우저(2023년 4월 기준 데이터)에서 지원돼요. Safari 브라우저는 15.4 버전(2022년 3월 출시)에서 지원을 추가했어요. Safari 15.3 이하를 지원해야 한다면 focus-visible polyfill을 사용하거나 :focus pseudo-class로 fallback을 제공할 수 있어요.

activeClassName

theme.activeClassName은 Button이나 ActionIcon처럼 active 스타일이 있는 요소에 추가되는 CSS 클래스예요. 모든 인터랙티브 컴포넌트의 active 스타일을 커스터마이즈하는 데 사용할 수 있어요.

import { MantineProvider, Button } from '@mantine/core';
import classes from './active.module.css';

function Demo() {
  return (
    <MantineProvider theme={{ activeClassName: classes.active }}>
      <Button>Press me to see active styles</Button>
    </MantineProvider>
  );
}

모든 컴포넌트의 active 스타일을 비활성화하려면 theme.activeClassName을 빈 문자열로 설정해요:

import { MantineProvider, Button } from '@mantine/core';

function Demo() {
  return (
    <MantineProvider theme={{ activeClassName: '' }}>
      <Button>No active styles</Button>
    </MantineProvider>
  );
}

defaultRadius

theme.defaultRadius는 Button이나 TextInput 같은 대부분의 컴포넌트에서 기본 border-radius 속성을 제어해요. theme.radius의 값 중 하나로 설정하거나 정확한 값을 사용하기 위해 숫자/문자열로 설정할 수 있어요. 숫자는 픽셀로 취급되지만 rem으로 변환된다는 점에 주의하세요. 예를 들어 theme.defaultRadius: 4는 0.25rem으로 변환돼요. rem 변환에 대해 더 자세히 알아보려면 rem units 가이드를 참고하세요.

import { MantineProvider, TextInput, Button } from '@mantine/core';

function Demo() {
  return (
    <MantineProvider theme={{ defaultRadius: 'lg' }}>
      <Button>Button with defaultRadius</Button>
    </MantineProvider>
  );
}

cursorType

theme.cursorType은 기본적으로 cursor: pointer 스타일이 없는 인터랙티브 요소의 기본 커서 타입을 제어해요. 예를 들어 Checkbox와 NativeSelect.

import { MantineProvider, createTheme, Checkbox } from '@mantine/core';

const theme = createTheme({
  cursorType: 'pointer',
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Checkbox label="Pointer cursor" />
    </MantineProvider>
  );
}

defaultGradient

theme.defaultGradient는 variant="gradient"를 지원하는 컴포넌트(Button, ActionIcon, Badge 등)의 기본 gradient 구성을 제어해요.

import { MantineProvider, createTheme, Button } from '@mantine/core';

const theme = createTheme({
  defaultGradient: {
    from: 'orange',
    to: 'red',
    deg: 45,
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Button variant="gradient">Button with custom default gradient</Button>
    </MantineProvider>
  );
}

fontWeights

theme.fontWeights는 모든 컴포넌트에서 사용되는 font-weight 값을 제어해요. 기본값은 regular: 400, medium: 600, bold: 700이에요. 각 값은 CSS 변수에 매핑돼요: --mantine-font-weight-regular, --mantine-font-weight-medium, --mantine-font-weight-bold.

예를 들어 medium font weight를 600에서 500(Mantine 8의 기본값)으로 되돌리려면:

import { createTheme, MantineProvider } from '@mantine/core';

const theme = createTheme({
  fontWeights: {
    medium: '500',
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      {/* Your app here */}
    </MantineProvider>
  );
}

components

theme.components는 컴포넌트의 기본 props와 classNames 및 styles 속성으로 스타일을 재정의할 수 있게 해줘요. 이 기능들에 대해 더 자세히 알아보려면 기본 props와 Styles API 가이드를 참고하세요.

other

theme.other는 theme 객체로 접근하고 싶은 다른 속성을 저장하는 데 사용할 수 있는 객체예요.

import { createTheme, MantineProvider } from '@mantine/core';

const theme = createTheme({
  other: {
    charcoal: '#333333',
    primaryHeadingSize: 45,
    fontWeights: {
      bold: 700,
      extraBold: 900,
    },
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      {/* Your app here */}
    </MantineProvider>
  );
}

theme override 객체를 변수에 저장

theme override 객체를 변수에 저장하려면 createTheme 함수를 사용해요:

import { createTheme, MantineProvider } from '@mantine/core';

const myTheme = createTheme({
  primaryColor: 'orange',
  defaultRadius: 0,
});

function Demo() {
  return (
    <MantineProvider theme={myTheme}>
      {/* Your app here */}
    </MantineProvider>
  );
}

여러 theme override 병합

mergeThemeOverrides 함수를 사용해 여러 theme을 하나의 theme override 객체로 병합해요:

import {
  createTheme,
  MantineProvider,
  mergeThemeOverrides,
} from '@mantine/core';

const theme1 = createTheme({
  primaryColor: 'orange',
  defaultRadius: 0,
});

const theme2 = createTheme({
  cursorType: 'pointer',
});

// Note: It is better to store the theme override outside of the component body
// to prevent unnecessary re-renders
const myTheme = mergeThemeOverrides(theme1, theme2);

function Demo() {
  return (
    <MantineProvider theme={myTheme}>
      {/* Your app here */}
    </MantineProvider>
  );
}

use-mantine-theme 훅

useMantineTheme 훅은 MantineProvider 컨텍스트에서 theme 객체를 반환해요:

import { useMantineTheme } from '@mantine/core';

function Demo() {
  const theme = useMantineTheme();
  return <div style={{ color: theme.colors.blue[6] }}>Text</div>;
}

기본 theme

@mantine/core 패키지에서 기본 theme 객체를 import 할 수 있어요. 기본값을 가진 모든 theme 속성이 포함돼 있어요. MantineProvider에 theme override를 전달하면 기본 theme과 깊게 병합돼요.

import { DEFAULT_THEME } from '@mantine/core';

컴포넌트 밖에서 theme 접근

컴포넌트 밖에서 theme에 접근하려면 전체 theme 객체(theme override와 기본 theme이 병합된 것)를 만들어야 해요.

// theme.ts
import {
  createTheme,
  DEFAULT_THEME,
  mergeMantineTheme,
} from '@mantine/core';

const themeOverride = createTheme({
  primaryColor: 'orange',
  defaultRadius: 0,
});

export const theme = mergeMantineTheme(DEFAULT_THEME, themeOverride);

그러면 애플리케이션 어디서든 import 할 수 있어요:

import { theme } from './theme';

더 알아보기 (Learn more)