Ref
Learn about the $bindable ref prop.
Bits UI components with underlying HTML elements provide a ref
prop for direct element access.
For example, Accordion.Trigger
's ref
gives access to its rendered HTMLButtonElement
:
<script lang="ts">
import { Accordion } from "bits-ui";
let triggerRef = $state<HTMLButtonElement>();
function focusTrigger() {
triggerRef?.focus();
}
</script>
<button onclick={focusTrigger}>Focus trigger</button>
<Accordion.Trigger bind:ref={triggerRef}>
<!-- ... -->
</Accordion.Trigger>
With delegation
Bits UI tracks the reference to the underlying element using its id
attribute. This means that even if you use a custom element/component with delegation, the ref
prop will still work.
<script lang="ts">
import CustomButton from "./CustomButton.svelte";
import { Accordion } from "bits-ui";
let triggerRef = $state<HTMLButtonElement>();
function focusTrigger() {
triggerRef?.focus();
}
</script>
<Accordion.Trigger bind:ref={triggerRef}>
{#snippet child({ props })}
<CustomButton {...props} />
{/snippet}
</Accordion.Trigger>
One caveat is that if you wish to use a custom id
on the element, you must pass it to the component first, so it can be registered and associated with the ref
prop. The id
you pass will be passed down via the props
snippet prop on the child
snippet.
<script lang="ts">
import CustomButton from "./CustomButton.svelte";
import { Accordion } from "bits-ui";
let triggerRef = $state<HTMLButtonElement>();
function focusTrigger() {
triggerRef?.focus();
}
const myCustomId = "my-custom-id";
</script>
<Accordion.Trigger bind:ref={triggerRef} id={myCustomId}>
{#snippet child({ props })}
<CustomButton {...props} /> <!-- custom id will be passed down to the child -->
{/snippet}
</Accordion.Trigger>
The following example would not work, as the Accordion.Trigger
component has no idea what the id
of the CustomButton
is.
<script lang="ts">
import CustomButton from "./CustomButton.svelte";
import { Accordion } from "bits-ui";
let triggerRef = $state<HTMLButtonElement>();
function focusTrigger() {
triggerRef?.focus(); // will always be undefined
}
</script>
<Accordion.Trigger bind:ref={triggerRef}>
{#snippet child({ props })}
<CustomButton {...props} id="my-custom-id" /> <!-- this won't work -->
{/snippet}
</Accordion.Trigger>
Why Possibly null
?
The ref
prop may be null
until the element has mounted, especially with the many components that use conditional rendering. This HTMLElement | null
type mimics browser DOM methods like getElementById
.
WithElementRef
Bits UI exposes a WithElementRef
type which enables you to create your own components following the same ref
prop pattern.