테마 개요

테마 개요

Chakra UI의 테마 시스템을 설정하는 방법을 다루는 가이드예요. 이 글을 따라 설정하고 나면 성능 좋고 확장 가능한 스타일링 시스템을 손쉽게 구성할 수 있답니다.

출처: 문서

본문

아키텍처

Chakra UI 테마 시스템은 Panda CSS의 API 위에 만들어졌어요.

성능 좋고 확장 가능한 스타일링 시스템을 제공하기 위한 구조를 간단히 살펴볼게요.

  • defineConfig 함수를 사용해 스타일링 시스템 설정을 정의한다.
  • createSystem 함수를 사용해 스타일링 엔진을 만든다.
  • 스타일링 엔진을 ChakraProvider 컴포넌트에 전달한다.
import {
  ChakraProvider,
  createSystem,
  defaultConfig,
  defineConfig,
} from "@chakra-ui/react"

const config = defineConfig({
  theme: {
    tokens: {
      colors: {},
    },
  },
})

const system = createSystem(defaultConfig, config)

export default function App() {
  return (
    <ChakraProvider value={system}>
      <Box>Hello World</Box>
    </ChakraProvider>
  )
}

설정 (Config)

Chakra UI 시스템은 defineConfig 함수로 설정해요. 이 함수는 스타일링 시스템의 동작을 커스터마이징할 수 있는 설정 객체를 받아요.

설정을 정의한 뒤에는 createSystem 함수에 전달해 스타일링 엔진을 만들어요.

cssVarsRoot

cssVarsRoot는 토큰 CSS 변수가 적용될 루트 요소를 지정해요.

const config = defineConfig({
  cssVarsRoot: ":where(:root, :host)",
})

export default createSystem(defaultConfig, config)

cssVarsPrefix

cssVarsPrefix는 토큰 CSS 변수에 사용할 접두사(prefix)를 지정해요.

const config = defineConfig({
  cssVarsPrefix: "ck",
})

export default createSystem(defaultConfig, config)

globalCss

globalCss는 시스템에 전역 스타일을 적용할 때 사용해요.

const config = defineConfig({
  globalCss: {
    "html, body": {
      margin: 0,
      padding: 0,
    },
  },
})

export default createSystem(defaultConfig, config)

preflight

preflight는 시스템에 css 리셋 스타일을 적용할 때 사용해요.

const config = defineConfig({
  preflight: false,
})

export default createSystem(defaultConfig, config)

혹은 preflight 설정 속성을 이용해 css 리셋 스타일을 시스템에 적용할 수도 있어요. 특정 요소에 css 리셋 스타일을 적용하고 싶을 때 유용해요.

const config = defineConfig({
  preflight: {
    scope: ".chakra-reset",
  },
})

export default createSystem(defaultConfig, config)

theme

theme 설정 속성으로 시스템 테마를 정의할 수 있어요. 이 속성은 다음 속성들을 받아요.

  • breakpoints: 브레이크포인트 정의
  • keyframes: css 키프레임 애니메이션 정의
  • tokens: 토큰 정의
  • semanticTokens: 시맨틱 토큰 정의
  • textStyles: 타이포그래피 스타일 정의
  • layerStyles: 레이어 스타일 정의
  • animationStyles: 애니메이션 스타일 정의
  • recipes: 컴포넌트 레시피 정의
  • slotRecipes: 컴포넌트 슬롯 레시피 정의
const config = defineConfig({
  theme: {
    breakpoints: {
      sm: "320px",
      md: "768px",
      lg: "960px",
      xl: "1200px",
    },
    tokens: {
      colors: {
        red: "#EE0F0F",
      },
    },
    semanticTokens: {
      colors: {
        danger: { value: "{colors.red}" },
      },
    },
    keyframes: {
      spin: {
        from: { transform: "rotate(0deg)" },
        to: { transform: "rotate(360deg)" },
      },
    },
  },
})

export default createSystem(defaultConfig, config)

conditions

conditions 설정 속성으로 시스템에서 사용할 커스텀 선택자와 미디어 쿼리 조건을 정의할 수 있어요.

const config = defineConfig({
  conditions: {
    cqSm: "@container(min-width: 320px)",
    child: "& > *",
  },
})

export default createSystem(defaultConfig, config)

사용 예시:

<Box mt="40px" _cqSm={{ mt: "0px" }}>
  <Text>Hello World</Text>
</Box>

strictTokens

strictTokens 설정 속성으로 디자인 토큰만 사용하도록 강제할 수 있어요. 테마에 정의되지 않은 토큰을 사용하려 하면 TS 에러가 발생해요.

const config = defineConfig({
  strictTokens: true,
})

export default createSystem(defaultConfig, config)
// ❌ This will throw a TS error
<Box color="#4f343e">Hello World</Box>

// ✅ This will work
<Box color="red.400">Hello World</Box>

TypeScript와 함께 strictTokens를 쓴다면, 로컬 개발과 CI/CD에서 CLI typegen 명령을 실행해 토큰 타입이 테마와 동기화되도록 하세요.

TypeScript

시스템을 설정할 때(colors, space, fonts 등) CLI가 타입 정의를 생성해 테마와 @chakra-ui/react를 동기화해 줘요. 덕분에 타입 안전한 API와 자동 완성을 누릴 수 있답니다.

postinstall, CI, 모노레포에서 typegen을 실행하는 방법은 CLI 문서를 참고하세요.

npx @chakra-ui/cli typegen ./theme.ts

시스템 (System)

설정을 정의한 뒤에는 createSystem 함수에 전달해 스타일링 엔진을 만들어요. 반환된 system은 프레임워크에 종속되지 않는 자바스크립트 스타일링 엔진으로, 컴포넌트 스타일링에 사용할 수 있어요.

const system = createSystem(defaultConfig, config)

시스템은 다음 속성들을 포함해요.

token

token 함수는 원시 토큰 값 또는 css 변수를 가져오는 데 사용해요.

const system = createSystem(defaultConfig, config)

// raw token
system.token("colors.red.200")
// => "#EE0F0F"

// token with fallback
system.token("colors.pink.240", "#000")
// => "#000"

token.var 함수를 사용하면 css 변수를 얻을 수 있어요.

// css variable
system.token.var("colors.red.200")
// => "var(--chakra-colors-red-200)"

// token with fallback
system.token.var("colors.pink.240", "colors.red.200")
// => "var(--chakra-colors-red-200)"

중요한 점은 semanticTokens는 token이나 token.var를 쓰든 항상 css 변수를 반환한다는 거예요. 시맨틱 토큰은 테마에 따라 값이 바뀌기 때문이에요.

// semantic token
system.token("colors.danger")
// => "var(--chakra-colors-danger)"

system.token.var("colors.danger")
// => "var(--chakra-colors-danger)"

tokens

const system = createSystem(defaultConfig, config)

system.tokens.getVar("colors.red.200")
// => "var(--chakra-colors-red-200)"

system.tokens.expandReferenceInValue("3px solid {colors.red.200}")
// => "3px solid var(--chakra-colors-red-200)"

system.tokens.cssVarMap
// => Map { "colors": Map { "red.200": "var(--chakra-colors-red-200)" } }

system.tokens.flatMap
// => Map { "colors.red.200": "var(--chakra-colors-red-200)" }

css

css 함수는 chakra 스타일 객체를 emotion이나 styled-components 또는 그 외 스타일링 라이브러리에 전달할 수 있는 CSS 스타일 객체로 변환해 줘요.

const system = createSystem(defaultConfig, config)

system.css({
  color: "red.200",
  bg: "blue.200",
})

// => { color: "var(--chakra-colors-red-200)", background: "var(--chakra-colors-blue-200)" }

cva

cva 함수는 컴포넌트 레시피를 만드는 데 사용해요. props 집합과 함께 호출하면 스타일 객체를 반환하는 함수를 돌려줘요.

const system = createSystem(defaultConfig, config)

const button = system.cva({
  base: {
    color: "white",
    bg: "blue.500",
  },
  variants: {
    outline: {
      color: "blue.500",
      bg: "transparent",
      border: "1px solid",
    },
  },
})

button({ variant: "outline" })
// => { color: "blue.500", bg: "transparent", border: "1px solid" }

sva

sva 함수는 컴포넌트 슬롯 레시피를 만드는 데 사용해요. props 집합과 함께 호출하면 각 슬롯에 대한 스타일 객체를 반환하는 함수를 돌려줘요.

const system = createSystem(defaultConfig, config)

const alert = system.sva({
  slots: ["title", "description", "icon"],
  base: {
    title: { color: "white" },
    description: { color: "white" },
    icon: { color: "white" },
  },
  variants: {
    status: {
      info: {
        title: { color: "blue.500" },
        description: { color: "blue.500" },
        icon: { color: "blue.500" },
      },
    },
  },
})

alert({ status: "info" })
// => { title: { color: "blue.500" }, description: { color: "blue.500" }, icon: { color: "blue.500" } }

isValidProperty

isValidProperty 함수는 속성이 유효한지 확인할 때 사용해요.

const system = createSystem(defaultConfig, config)

system.isValidProperty("color")
// => true

system.isValidProperty("background")
// => true

system.isValidProperty("invalid")
// => false

splitCssProps

splitCssProps 함수는 props를 css props와 non-css props로 분리하는 데 사용해요.

const system = createSystem(defaultConfig, config)

system.splitCssProps({
  color: "red.200",
  bg: "blue.200",
  "aria-label": "Hello World",
})
// => [{ color: "red.200", bg: "blue.200" }, { "aria-label": "Hello World" }]

breakpoints

breakpoints 속성은 브레이크포인트를 조회할 때 사용해요.

const system = createSystem(defaultConfig, config)

system.breakpoints.up("sm")
// => "@media (min-width: 320px)"

system.breakpoints.down("sm")
// => "@media (max-width: 319px)"

system.breakpoints.only("md")
// => "@media (min-width: 320px) and (max-width: 768px)"

system.breakpoints.keys()
// => ["sm", "md", "lg", "xl"]

토큰 (Tokens)

토큰에 대해 더 자세히 알아보려면 tokens 섹션을 참고하세요.

레시피 (Recipes)

레시피에 대해 더 자세히 알아보려면 recipes 섹션을 참고하세요.

더 알아보기 (Learn more)

  • 토큰 문서에서 디자인 토큰 정의 방법을 알아보세요.
  • 레시피 문서에서 다중 변형 스타일 작성법을 알아보세요.