Child Snippet
Learn how to use the `child` snippet to render your own elements.
Usage
Many Bits UI components have a default HTML element that wraps their children
. For example, Accordion.Trigger
typically renders as:
<button>
{@render children()}
</button>
While you can set standard button attributes, you might need more control for:
- Applying Svelte transitions or actions
- Using custom components
- Scoped CSS
This is where the child
snippet comes in.
Components supporting render delegation accept an optional child prop, which is a Svelte snippet. When used, the component passes its attributes to this snippet, allowing you to apply them to any element.
Let's take a look at an example using the Accordion.Trigger
component:
<Accordion.Trigger>
{#snippet child({ props })}
<div {...props}>Open accordion item</div>
{/snippet}
</Accordion.Trigger>
The props
object includes event handlers, ARIA attributes, and any other attributes passed to Accordion.Trigger
. Note that when using child
, other children outside this snippet are ignored.
Custom IDs & Attributes
To use custom IDs, event handlers, or other attributes with a custom element, you must pass them to the component first. This is crucial because:
- Many Bits UI internals rely on specific IDs
- Props are merged using a
mergeProps
function to handle cancelling internal handlers, etc.
Correct usage:
<Accordion.Trigger id="my-custom-id" onclick={() => console.log("clicked")}>
<!-- your custom ID and event handler is now inside the `props` object -->
{#snippet child({ props })}
<div {...props}>Open accordion item</div>
{/snippet}
</Accordion.Trigger>
In this example, my-custom-id
, the click event handler, and my-custom-class are properly merged into the props
object, ensuring they work alongside Bits UI's internal logic.
Behind the scenes, components using the child prop typically implement logic similar to this:
<script lang="ts">
// other imports/props/logic omitted for brevity
let { child, children, ...restProps } = $props();
const trigger = makeTrigger();
const mergedProps = $derived(mergeProps(restProps, trigger.props));
</script>
{#if child}
{@render child({ props: mergedProps })}
{:else}
<button {...mergedProps}>
{@render children?.()}
</button>
{/if}