Iframe에서 Chakra UI 사용하기

Iframe에서 Chakra UI 사용하기 (Using Chakra UI in Iframe)

Iframe은 스타일과 로직을 별도의 컨텍스트로 격리할 때 유용해요. 예를 들어 Chakra 컴포넌트를 전용 샌드박스에서 전시하고 싶을 수 있습니다. Iframe 안에서 Chakra UI를 설치하고 사용하는 방법을 안내합니다.

출처: 문서

본문

Iframe은 스타일과 로직을 별도의 컨텍스트로 격리하는 데 유용해요. 예를 들어 Chakra 컴포넌트를 전용 샌드박스에서 보여주고 싶을 때 쓰입니다.

템플릿 (Template)

빠르게 시작하려면 다음 템플릿을 사용하세요.

설치 (Installation)

최소 Node 버전은 Node.20.x입니다.

의존성 설치 (Install dependencies)

npm i @chakra-ui/react @emotion/react @emotion/cache react-frame-component

추가로 사용되는 패키지들은 다음과 같아요.

  • react-frame-component — iframe을 쉽게 생성하는 데 사용
  • @emotion/cache — 스타일을 위한 커스텀 삽입 지점을 생성하는 데 사용

스니펫 추가 (Add snippets)

스니펫은 UI를 더 빨리 구축하는 데 사용할 수 있는 사전 빌드된 컴포넌트예요. @chakra-ui/cli를 사용해 스니펫을 프로젝트에 추가할 수 있습니다.

npx @chakra-ui/cli snippet add

tsconfig 업데이트 (Update tsconfig)

TypeScript를 사용한다면 tsconfig 파일의 compilerOptions에 다음 옵션을 포함하도록 업데이트해야 해요.

{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "skipLibCheck": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Iframe 설정 (Setup Iframe)

react-frame-component 패키지를 사용해 iframe을 설정하는 components/ui/iframe-provider.tsx 파일을 만드세요.

import {
  ChakraProvider,
  EnvironmentProvider,
  defaultSystem,
} from "@chakra-ui/react"
import createCache from "@emotion/cache"
import { CacheProvider } from "@emotion/react"
import Iframe, { FrameContextConsumer } from "react-frame-component"

function memoize<T extends object, R>(func: (arg: T) => R): (arg: T) => R {
  const cache = new WeakMap<T, R>()
  return (arg: T) => {
    if (cache.has(arg)) return cache.get(arg)!
    const ret = func(arg)
    cache.set(arg, ret)
    return ret
  }
}

const createCacheFn = memoize((container: HTMLElement) =>
  createCache({ container, key: "frame" }),
)

export const IframeProvider = (props: React.PropsWithChildren) => {
  const { children } = props
  return (
    <Iframe>
      <FrameContextConsumer>
        {(frame) => {
          const head = frame.document?.head
          if (!head) return null
          return (
            <CacheProvider value={createCacheFn(head)}>
              <EnvironmentProvider value={() => head.ownerDocument}>
                <ChakraProvider value={defaultSystem}>
                  {children}
                </ChakraProvider>
              </EnvironmentProvider>
            </CacheProvider>
          )
        }}
      </FrameContextConsumer>
    </Iframe>
  )
}

provider 설정 (Setup provider)

애플리케이션 루트에서 components/ui/provider 컴포넌트에 생성된 Provider 컴포넌트로 애플리케이션을 감싸세요.

이 provider는 다음을 조합해요.

  • 스타일링 시스템을 위한 @chakra-ui/react의 ChakraProvider
  • 컬러 모드를 위한 next-themes의 ThemeProvider
import { Provider } from "@/components/ui/provider"
import React from "react"
import ReactDOM from "react-dom/client"
import App from "./App"

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <Provider>
      <App />
    </Provider>
  </React.StrictMode>,
)

IframeProvider 사용하기 (Use the IframeProvider)

애플리케이션의 어떤 컴포넌트든 IframeProvider 컴포넌트로 감싸면 iframe 안에서 렌더링할 수 있어요.

import { Button, Container, Heading, Stack } from "@chakra-ui/react"
import { IframeProvider } from "./components/ui/iframe-provider"

function App() {
  return (
    <Container py="8">
      <Heading mb="5">Outside Iframe</Heading>

      <IframeProvider>
        <Stack p="6" align="flex-start" border="1px solid red">
          <Heading>Inside Iframe</Heading>
          <Button>Click me</Button>
        </Stack>
      </IframeProvider>
    </Container>
  )
}

export default App

커스터마이즈 (Customization)

createSystem 함수로 커스텀 테마를 만들었다면, iframe 안에서 사용되도록 IframeProvider와 Provider 컴포넌트에 전달했는지 확인하세요.

예를 들어 커스텀 테마를 만들었다고 가정해 볼게요.

export const system = createSystem(defaultConfig, {
  theme: { colors: {} },
})

그다음 그것을 IframeProvider와 Provider 컴포넌트에 전달하세요.

<ChakraProvider value={system}>{/* ... */}</ChakraProvider>

더 알아보기 (Learn more)