Environment
Set up components for custom environments like iframes, Shadow DOM, or Electron.
Motivation
We use Zag.js internally, which
relies on DOM query methods like document.querySelectorAll
and document.getElementById
. In
custom environments like iframes, Shadow DOM, or Electron, these methods might not work as expected.
To handle this, Ark UI includes the EnvironmentProvider
, allowing you to set the appropriate root
node or document, ensuring correct DOM queries.
Setup
To support custom environments like an iframe, Shadow DOM or Electron, render the
EnvironmentProvider
component to provide the environment context to all Ark UI components.
import { EnvironmentProvider } from '@ark-ui/react/environment'
import Frame from 'react-frame-component'
export const App = () => {
return (
<Frame title="IFrame Context">
<EnvironmentProvider>{/* Your App */}</EnvironmentProvider>
</Frame>
)
}
import { EnvironmentProvider } from '@ark-ui/solid/environment'
export const App = () => {
return (
<iframe title="IFrame Context">
<EnvironmentProvider>{/* Your App */}</EnvironmentProvider>
</iframe>
)
}
<script setup lang="ts">
import { EnvironmentProvider } from '@ark-ui/vue/environment'
</script>
<template>
<iframe title="IFrame Context">
<EnvironmentProvider><!-- Your App --></EnvironmentProvider>
</iframe>
</template>
Usage in iframe
The EnvironmentProvider
component will automatically detect the current environment and set the
correct environment context. However, you can also manually set the Document
like shown in this
React example below:
import Frame, { FrameContextConsumer } from 'react-frame-component'
import { EnvironmentProvider } from '@ark-ui/react'
export const App = () => (
<Frame title="IFrame Context">
<FrameContextConsumer>
{({ document }) => (
<EnvironmentProvider value={document}>{/* Your App */}</EnvironmentProvider>
)}
</FrameContextConsumer>
</Frame>
)
Usage in Shadow DOM
Here's an example of how to set the EnvironmentProvider
's value with Shadow DOM in Solid.js
Portal
component.
import { EnvironmentProvider } from '@ark-ui/react'
import { Index, Portal } from 'solid-js/web'
export const App = () => {
let portalNode
return (
<Portal ref={portalNode} useShadow={true}>
<EnvironmentProvider value={() => portalNode?.shadowRoot ?? document}>
{/* Your App */}
</EnvironmentProvider>
</Portal>
)
}
Context
Use the useEnvironmentContext
hook to access the RootNode
, Document
, and Window
.
import { useEnvironmentContext } from '@ark-ui/react/environment'
export const Usage = () => {
const { getRootNode } = useEnvironmentContext()
return <pre>{JSON.stringify(getRootNode(), null, 2)}</pre>
}
import { useEnvironmentContext } from '../use-environment-context'
export const Usage = () => {
const environment = useEnvironmentContext()
return <pre>{JSON.stringify(environment().getRootNode(), null, 2)}</pre>
}
<script setup lang="ts">
import { useEnvironmentContext } from '@ark-ui/vue/environment'
const environment = useEnvironmentContext()
</script>
<template>
<pre>{{ JSON.stringify(environment?.getRootNode(), null, 2) }}</pre>
</template>