Ref

Learn about the $bindable ref prop.

llms.txt

The ref prop provides direct access to the underlying HTML elements in Bits UI components, enabling you to manipulate the DOM when necessary.

Basic Usage

Every Bits UI component that renders an HTML element exposes a ref prop that you can bind to access the rendered element. This is particularly useful for programmatically manipulating the element, such as focusing inputs or measuring dimensions.

	<script lang="ts">
	import { Accordion } from "bits-ui";
 
	let triggerRef = $state<HTMLButtonElement | null>(null);
 
	function focusTrigger() {
		triggerRef?.focus();
	}
</script>
 
<button onclick={focusTrigger}>Focus trigger</button>
 
<Accordion.Trigger bind:ref={triggerRef}>Trigger content</Accordion.Trigger>

With Child Snippet

Bits UI uses element IDs to track references to underlying elements. This approach ensures that the ref prop works correctly even when using the child snippet.

Simple Delegation Example

The ref binding will automatically work with delegated child elements/components.

	<script lang="ts">
	import CustomButton from "./CustomButton.svelte";
	import { Accordion } from "bits-ui";
 
	let triggerRef = $state<HTMLButtonElement | null>(null);
 
	function focusTrigger() {
		triggerRef?.focus();
	}
</script>
 
<Accordion.Trigger bind:ref={triggerRef}>
	{#snippet child({ props })}
		<CustomButton {...props} />
	{/snippet}
</Accordion.Trigger>

Using Custom IDs

When you need to use a custom id on the element, pass it to the parent component first so it can be correctly registered with the ref binding:

	<script lang="ts">
	import CustomButton from "./CustomButton.svelte";
	import { Accordion } from "bits-ui";
 
	let triggerRef = $state<HTMLButtonElement | null>(null);
	const myCustomId = "my-custom-id";
</script>
 
<Accordion.Trigger bind:ref={triggerRef} id={myCustomId}>
	{#snippet child({ props })}
		<!-- The custom ID will be included in props -->
		<CustomButton {...props} />
	{/snippet}
</Accordion.Trigger>

Common Pitfalls

Avoid setting the id directly on the child component/element, as this breaks the connection between the ref binding and the element:

	<!-- ❌ This won't work correctly -->
<Accordion.Trigger bind:ref={triggerRef}>
	{#snippet child({ props })}
		<CustomButton {...props} id="my-custom-id" />
	{/snippet}
</Accordion.Trigger>

In this example, the Accordion.Trigger component can't track the element because it doesn't know the custom ID.

Why Possibly null?

The ref value may be null until the component mounts in the DOM. This behavior is consistent with native DOM methods like getElementById which can return null.

Creating Your Own ref Props

To implement the same ref pattern in your custom components, Bits UI provides a WithElementRef type helper. This enables you to create type-safe components that follow the same pattern.

	<script lang="ts">
	import { WithElementRef } from "bits-ui";
	import type { HTMLButtonAttributes } from "svelte/elements";
 
	// Define props with the ref type
	let {
		ref = $bindable(null),
		children,
		...rest
	}: WithElementRef<
		HTMLButtonAttributes & {
			yourPropA: string;
			yourPropB: number;
		},
		HTMLButtonElement
	> = $props();
</script>
 
<button bind:this={ref} {...rest}>
	{@render children?.()}
</button>