ComboBox fires change events on blur when isReadOnly, clearing a fully controlled value that is not in the collection
Los mantenedores suelen responder en 1 día
@ayuxy027 ya está trabajando en esto.
Desde el 28/10/2026.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 74/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- react, typescript
- Área
- accessibility, frontend
Línea de trabajo
Empieza en useComboBoxState y sigue cómo setFocused gestiona el desenfoque y confirma el valor cuando isReadOnly es true. Reproduce el problema con el ejemplo de ComboBox controlado proporcionado, usando una lista de opciones vacía y una clave seleccionada que no está en la colección. Se considera resuelto cuando el desenfoque deja sin cambios la selección controlada y el texto de entrada, y no emite un cambio con null.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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
- Lenguaje dominante
- TypeScript
- Estrellas
- 16k
- Forks
- 1.6k
- Merge medio
- 2 d 17 h
- PR fusionados (30 d)
- 41
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de adobe/react-spectrum
-
S2 quiet Picker menu is always 192px wide: its width calc() has no unitPosiblemente ocupada @darshpatel1052 la tomó hoy. Abiertowaiting on author
Dificultad 2/5 Menos de una hora Aptitud para principiantes 88/100
adobe/react-spectrum#10909 · 3 comentarios ·
Los mantenedores suelen responder en 1 día
-
DatePicker omits timezone for initially empty fields despite zoned placeholderValuePosiblemente ocupada @mrlexcoder la tomó hace 1 día. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
adobe/react-spectrum#10900 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
Separator adds a redundant role="separator" to its default <hr>Posiblemente ocupada @Janani-bn la tomó hace 1 día. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
adobe/react-spectrum#10894 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
ComboBox with selectionMode="multiple": Cmd/Ctrl+A does nothing while the popover is openPosiblemente ocupada @mangeshraut712 la tomó hace 7 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
adobe/react-spectrum#10866 ·
Los mantenedores suelen responder en 1 día
-
CheckboxGroup: `validationBehavior="aria"` is ignored by its checkboxes since 1.18Posiblemente ocupada @mangeshraut712 la tomó hace 7 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
adobe/react-spectrum#10856 ·
Los mantenedores suelen responder en 1 día
Todos los issues de adobe/react-spectrum
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
riverqueue/river#1576 ·
Los mantenedores suelen responder en 1 día
-
[bug] A prompt queued during a run is assessed without its textPosiblemente ocupada @jwiegley la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
DevMortimer/pi-warden#211 ·
Los mantenedores suelen responder en 1 día
-
enhancement
Dificultad 1/5 Menos de una hora Aptitud para principiantes 84/100
mattermost/compass-design#191 ·
Los mantenedores suelen responder en 1 día
-
Add unit tests for the organization admin role checkPosiblemente ocupada @SaffuSafwan la tomó hoy. Abiertoarea/core good first issue help wanted
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
elmohq/elmo#1095 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
HorusGoul/trizum#559 · 1 comentario ·
Los mantenedores suelen responder en 1 día