Description
Describe the bug
Description
When programmatically changing the value of a Combobox component created following the docs at https://next.bits-ui.com/docs/components/combobox, the dropdown selection updates correctly, but the input field text doesn't reflect the change.
Steps to Reproduce
Create a reusable Combobox component following the documentation:
<script lang="ts">
import { Combobox, type WithoutChildrenOrChild, mergeProps } from "bits-ui";
import { Icon, ChevronUpDown } from "svelte-hero-icons";
type Item = { value: string; label: string };
type Props = Combobox.RootProps & {
items: Item[];
inputProps?: WithoutChildrenOrChild<Combobox.InputProps>;
contentProps?: WithoutChildrenOrChild<Combobox.ContentProps>;
};
let {
items,
value = $bindable(),
open = $bindable(false),
inputProps,
contentProps,
...restProps
}: Props = $props();
let searchValue = $state("");
const filteredItems = $derived.by(() => {
if (searchValue === "") return items;
return items.filter((item) => item.label.toLowerCase().includes(searchValue.toLowerCase()));
});
function handleInput(e: Event & { currentTarget: HTMLInputElement }) {
searchValue = e.currentTarget.value;
}
function handleOpenChange(newOpen: boolean) {
if (!newOpen) searchValue = "";
}
const mergedRootProps = $derived(mergeProps(restProps, { onOpenChange: handleOpenChange }));
const mergedInputProps = $derived(mergeProps(inputProps, { oninput: handleInput }));
</script>
<Combobox.Root bind:value bind:open {...mergedRootProps} type="single">
<div class="relative">
<Combobox.Input
{...mergedInputProps}
class="border-input bg-background placeholder:text-muted-foreground flex h-10 w-full rounded-md border px-3 py-2 text-base file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm"
/>
<Combobox.Trigger class="absolute end-3 top-1/2 size-6 -translate-y-1/2"><Icon src={ChevronUpDown} class="w-5 h-5 text-neutral-600" /></Combobox.Trigger>
</div>
<Combobox.Portal>
<Combobox.Content {...contentProps} class="z-50 bg-white w-[var(--bits-combobox-anchor-width)] min-w-[var(--bits-combobox-anchor-width)] rounded-md border shadow-md outline-none mt-2 p-1">
{#each filteredItems as item, i (item.value)}
<Combobox.Item value={item.value} label={item.label} class="relative flex w-full select-none items-center rounded-sm p-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 cursor-pointer">
{#snippet children({ selected })}
<div class="flex flex-col w-full">
<span class={selected ? "font-medium text-red-500" : ""}>{item.label}</span>
</div>
{/snippet}
</Combobox.Item>
{:else}
<span> No results found </span>
{/each}
</Combobox.Content>
</Combobox.Portal>
</Combobox.Root>
Use this component in another file with programmatic value changes:
let myValue = $state("");
const testItems = [
{ value: "mango", label: "Mango" },
{ value: "watermelon", label: "Watermelon" },
{ value: "apple", label: "Apple" },
];
<button onclick={() => (myValue = "apple")}> Select Apple </button>
<Combobox items={testItems} bind:value={myValue} />
Click the "Select Apple" button
Expected Behavior
When clicking the "Select Apple" button (setting myValue = "apple" programmatically), both the dropdown selection AND the input field text should update to display "Apple".
Actual Behavior
The dropdown correctly shows "Apple" as selected, but the input field remains empty or unchanged.
Reproduction
https://stackblitz.com/edit/github-cfbnbfta-fwh7ndgr?file=src%2Froutes%2F%2Bpage.svelte
Logs
System Info
"bits-ui": "1.3.13",
"svelte": "^5.0.0",
Severity
annoyance