Composition
Learn how to compose default components with custom elements
The asChild Prop
In Ark UI, the asChild
prop lets you integrate custom components, ensuring consistent styling and
behavior while promoting flexibility and reusability. All Ark components that render a DOM element
accept the asChild
prop.
Here's an example using asChild
to integrate a custom Button
component within a Popover
:
import { Button } from '@acme/ui-lib'
import { Popover } from '@ark-ui/react'
export const AsChild = () => (
<Popover.Root>
<Popover.Trigger asChild>
<Button>Open</Button>
</Popover.Trigger>
</Popover.Root>
)
import { Button } from '@acme/ui-lib'
import { Popover } from '@ark-ui/solid'
export const Basic = () => (
<Popover.Root>
<Popover.Trigger asChild={(props) => <Button {...props()} />}>Open</Popover.Trigger>
</Popover.Root>
)
<script setup lang="ts">
import { Button } from '@acme/ui-lib'
import { Popover } from '@ark-ui/vue'
</script>
<template>
<Popover.Root>
<Popover.Trigger asChild>
<Button>Open</Button>
</Popover.Trigger>
</Popover.Root>
</template>
In this example, the asChild
prop allows the Button
to be used as the trigger for the Popover
,
inheriting its behaviors from Popover.Trigger.
The Ark Factory
You can use the ark
factory to create your own elements that work just like Ark UI components.
Example not found
import { ark } from '@ark-ui/solid'
export const ArkFactory = () => (
<ark.div
id="parent"
class="parent"
style={{ background: 'red' }}
asChild={(props) => (
<ark.span {...props({ id: 'child', class: 'child', style: { color: 'blue' } })} />
)}
>
Ark UI
</ark.div>
)
<script setup lang="ts">
import { ark } from '@ark-ui/vue'
</script>
<template>
<ark.div id="parent" className="parent" :style="{ background: 'red' }" asChild>
<ark.span id="child" className="child" :style="{ color: 'blue' }">Ark UI</ark.span>
</ark.div>
</template>
This will produce the following HTML:
<span id="child" class="parent child" style="background: red; color: blue;">Ark UI</span>
Limitations
When using the asChild
prop, ensure you pass only a single child element. Passing multiple children may cause rendering issues.
Certain components, such as Checkbox.Root
or RadioGroup.Item
, have specific requirements for their child elements.
For instance, they may require a label element as a child.
If you change the underlying element type, ensure it remains accessible and functional.