ComboBox fires change events on blur when isReadOnly, clearing a fully controlled value that is not in the collection
I maintainer di solito rispondono entro 1 giorno
@mangeshraut712 ci sta già lavorando.
Dal 27/10/2026.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 74/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- react, typescript
- Ambito
- accessibility, frontend
Direzione di ricerca
Inizia da useComboBoxState e segui come setFocused gestisce la perdita del focus e conferma il valore quando isReadOnly è true. Riproduci il problema con l’esempio controllato di ComboBox fornito, usando un elenco di opzioni vuoto e una chiave selezionata assente dalla collection. Il problema è risolto quando la perdita del focus lascia invariati la selezione controllata e il testo di input e non emette una modifica con null.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Provide a general summary of the issue here
A fully controlled ComboBox with isReadOnly fires change events with null on blur when the currently selected key is not present in the collection. This becomes an issue when, for example, options are fetched asynchronously and the list is empty while the dropdown is closed.
isReadOnly seems to only be consulted when to decide whether to auto-open the dropdown on focus. Committing the value runs regardless of isReadOnly. Apps that derive the input text from the selection end up clearing a field the user never changed.
Simple workarounds exist, making this somewhat non-critical. But it might still be a bit confusing when it's happening.
🤔 Expected Behavior?
A ComboBox with isReadOnly should not attempt to commit values on blur. The user cannot change the selection or the input while read-only, so a blur should be a no-op.
😯 Current Behavior
- The input shows the selected label on mount
- Click into the input (focus)
- Click/tab out (blur)
- Change event fires with
nulland the input is cleared
💁 Possible Solution
Gate the blur commit on isReadOnly in useComboBoxState's setFocused.
🔦 Context
We fetch a list of objects from our server, which cannot be modified anymore. When rendered in a grid, we want to be able to append more objects to that list and we want them to be in the same grid as the ones returned from the server. For the fields related to the existing objects, we set isReadOnly to show them to the user, without the user being able to modify them. New objects are appended and can be modified before saving.
One of the fields in those objects is handled by the ComboBox. When a user types in the ComboBox, we query our server for a list of results. The query requires a minimum of 3 characters. Querying is only done on input change, so it never gets triggered unless the user actually is typing in the input field. Hence why the items list is empty when the blur happens. When selecting an option, the input value is changed to match the queried name.
There are simple workarounds, like ensuring that the items always contain at least the selected item, or defaulting a null selection change back to the selected item if isReadOnly.
🖥️ Steps to Reproduce
import type { Meta, StoryObj } from "@storybook/react-vite";
import { useState } from "react";
import type { Key } from "react-aria-components";
import {
Button,
ComboBox,
Input,
Label,
ListBox,
ListBoxItem,
Popover,
} from "react-aria-components";
// Repro: a read-only, fully controlled ComboBox (value + inputValue) whose
// options are fetched asynchronously while typing. When the menu is closed
// there is no active query, so `items` is empty and the selected key is not in
// the collection. Focusing then blurring the input clears it, even though the
// field is read-only and nothing changed: RAC still runs the blur commit and,
// because the selected key can't be resolved in the empty collection, fires
// onChange(null).
const styles = {
root: { display: "flex", flexDirection: "column", gap: 4, maxWidth: 320 },
field: {
display: "flex",
alignItems: "center",
border: "1px solid #D9D9D9",
borderRadius: 6,
background: "#FFF",
},
input: { flex: 1, border: "none", outline: "none", padding: "8px 12px" },
button: { border: "none", background: "transparent", padding: "0 10px" },
popover: {
background: "#FFF",
border: "1px solid #D9D9D9",
borderRadius: 6,
boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
minWidth: "var(--trigger-width)",
padding: 4,
},
item: { padding: "8px 12px", borderRadius: 4, outline: "none" },
} satisfies Record<string, React.CSSProperties>;
const meta = { title: "Bugs/RAC ComboBox ReadOnly Blur" } satisfies Meta;
export default meta;
type Story = StoryObj<typeof meta>;
type Country = { id: string; name: string };
function Repro({ options }: { options: Countryy[] }) {
// Pre-selected value with its display text, as if restored from saved data.
const [value, setValue] = useState<Key | null>("fi");
const [inputValue, setInputValue] = useState("Finland");
return (
<ComboBox
aria-label="Country"
items={options}
value={value}
inputValue={inputValue}
onChange={(key) => {
const match = options.find((c) => c.id === key) ?? null;
setValue(match?.id ?? null);
setInputValue(match?.name ?? "");
}}
onInputChange={setInputValue}
isReadOnly
allowsEmptyCollection
style={styles.root}
>
<Label>Country</Label>
<div style={styles.field}>
<Input placeholder="Select a country" style={styles.input} />
<Button style={styles.button}>▼</Button>
</div>
<Popover style={styles.popover}>
<ListBox<Country>>
{(item) => (
<ListBoxItem id={item.id} style={styles.item}>
{item.name}
</ListBoxItem>
)}
</ListBox>
</Popover>
</ComboBox>
);
}
// No active query -> empty options. Focus + blur clears the input.
export const Bug: Story = { render: () => <Repro options={[]} /> };
// Selected item present in the collection. Focus + blur keeps the value.
export const Ok: Story = {
render: () => <Repro options={[{ id: "fi", name: "Finland" }]} />,
};
Version
react-aria-components: 1.22.0
What browsers are you seeing the problem on?
Other
If other, please specify.
all
What operating system are you using?
Linux, MacOs, Windows
🧢 Your Company/Team
No response
🕷 Tracking Issue
No response
- Lingua principale
- TypeScript
- Stelle
- 16k
- Fork
- 1.6k
- Merge medio
- 2g 19h
- PR unite (30g)
- 41
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di adobe/react-spectrum
-
Difficoltà 2/5 Meno di un'ora Idoneità per principianti 88/100
adobe/react-spectrum#10909 ·
I maintainer di solito rispondono entro 1 giorno
-
DatePicker omits timezone for initially empty fields despite zoned placeholderValueForse già presa Una pull request collegata a questa issue è aperta o già unita. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
adobe/react-spectrum#10900 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Separator adds a redundant role="separator" to its default <hr>Forse già presa @Janani-bn l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
adobe/react-spectrum#10894 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
ComboBox with selectionMode="multiple": Cmd/Ctrl+A does nothing while the popover is openForse già presa @mangeshraut712 l’ha presa 6 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
adobe/react-spectrum#10866 ·
I maintainer di solito rispondono entro 1 giorno
-
CheckboxGroup: `validationBehavior="aria"` is ignored by its checkboxes since 1.18Forse già presa @mangeshraut712 l’ha presa 7 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
adobe/react-spectrum#10856 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di adobe/react-spectrum
Issue simili
-
mobile-app
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
Open-Locker/Open-Locker#352 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
leanprover-community/lean4game#589 ·
I maintainer di solito rispondono entro 2 giorni
-
Add: CS Action BGApertacheck:passed streams:add
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
unocss/unocss#5421 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno