diff --git a/frontend/src/components/SortControl.dom.test.tsx b/frontend/src/components/SortControl.dom.test.tsx index 2459bb1f..2ff69e73 100644 --- a/frontend/src/components/SortControl.dom.test.tsx +++ b/frontend/src/components/SortControl.dom.test.tsx @@ -47,6 +47,11 @@ describe("SortControl", () => { expect(none.value).toBe(""); }); + it("falls back to the first option (not a blank select) for an unavailable key without defaultLabel", () => { + renderControl({ key: "ghost", dir: "asc" }); + expect((screen.getByRole("combobox") as HTMLSelectElement).value).toBe("date"); + }); + it("picking a new option fires onChange at that option's defaultDir", () => { const { onChange } = renderControl({ key: "title", dir: "asc" }); fireEvent.change(screen.getByRole("combobox"), { target: { value: "date" } }); diff --git a/frontend/src/components/SortControl.tsx b/frontend/src/components/SortControl.tsx index d4fd080f..cf3be5c6 100644 --- a/frontend/src/components/SortControl.tsx +++ b/frontend/src/components/SortControl.tsx @@ -36,10 +36,14 @@ export default function SortControl({ const active = sort && options.some((o) => o.key === sort.key) ? sort : null; const activeOpt = active ? options.find((o) => o.key === active.key) : undefined; const showArrow = !!activeOpt && !activeOpt.directionless; + // An always-sorted view (no `defaultLabel`) must still show a real option when the current key isn't + // offered (a stale/out-of-scope sort) — fall back to the first option rather than a blank select + // (which also trips React's controlled-value warning). Views with a "no sort" option keep it. + const selectValue = active?.key ?? (defaultLabel === undefined ? (options[0]?.key ?? "") : ""); return (