Skip to content

fix(dropdown): keep query-sourced selections while the options query loads - #3330

Open
alecrt wants to merge 1 commit into
evidence-dev:mainfrom
alecrt:pr/dropdown-pending-options
Open

fix(dropdown): keep query-sourced selections while the options query loads#3330
alecrt wants to merge 1 commit into
evidence-dev:mainfrom
alecrt:pr/dropdown-pending-options

Conversation

@alecrt

@alecrt alecrt commented Sep 4, 2026

Copy link
Copy Markdown

Summary

Prevents single-select and multi-select dropdowns from prematurely clearing query-sourced selections when static dropdown_option children (e.g. an "All" option) are present, ensuring URL-hydrated filter values and initial_value selections survive initial page hydration while options are loading.

Problem / Motivation

A dropdown often mixes static dropdown_option children (typically an "All" or default entry) with dynamic options populated from data=:

<Dropdown data={categories} id="category" value_column="code" initial_value="all">
    <DropdownOption value="all" label="All Categories" />
</Dropdown>

Currently, isDropdownValueValid (core/src/user-components/tags/dropdown/validation.ts) switches validation on as soon as static options exist (hasStaticOptions). Because the options query has not resolved on first paint, availableValues only contains the static options.

What went wrong:

  • Any query-sourced selection (such as a link opened with ?category=electronics) fails validation against the static option set alone and is cleared on initial mount.
  • The URL filter writer subsequently detects the empty value and strips the query parameter from the browser URL, destroying shareable/bookmarkable links.
  • initial_value suffers the same failure whenever it refers to a query-sourced value.
  • Conversely, dropdowns with no static children keep their query-sourced values as expected, which makes this bug particularly confusing and difficult to diagnose.

Solution

  • Introduce an explicit optionsQueryPending state (queryConfig !== undefined && optionsQuery.result === undefined) indicating that an options query is configured but has not yet produced a result.
  • While optionsQueryPending is true, isDropdownValueValid preserves the current selection regardless of static options.
  • Once the options query settles, standard validation resumes immediately, ensuring cascading dropdowns still clear genuinely stale selections when dependent parameters change.
  • A query that encounters an error is treated conservatively in the same way, consistent with Evidence's existing handling for empty query results: preserving a selection that cannot currently be checked is safer than clearing a valid one.
  • Dropdowns without an options query have no pending state and continue validating against static options exactly as before.

Testing

  • Added unit tests in core/src/user-components/tags/dropdown/validation.test.ts:
    • keeps a query-sourced value while the options query is still pending, despite static options
    • validates again as soon as the options query settles
    • leaves dropdowns without a query untouched: no pending state, static options still validate
  • Ran unit tests via Vitest: 10/10 passed cleanly.
  • Ran type checks via pnpm --filter @evidence/core check: 0 errors.

Checklist

  • Changes are confined to core/** (no files at repository root).
  • Follows project code style and conventions.
  • Commit message follows Conventional Commits format.

…loads

A dropdown can mix a static `dropdown_option` child (typically an "All"
entry) with options coming from `data=`. `isDropdownValueValid` switched
validation on as soon as static options existed, so before the query
returned the known universe was just the static values — and any legitimate
query-sourced selection was cleared.

The visible damage is on URL-hydrated values: `?status=active` on a page
whose dropdown declares `{% dropdown_option value="%" %}` and pulls the rest
from a query resets to empty on first paint, and the writer then drops the
parameter from the URL too, so the link is not shareable. `initial_value`
suffers the same fate whenever it names a query-sourced option.

Adds an explicit "options query configured but not settled" state: while it
holds, the value is kept whatever the static options say. Validation resumes
untouched once the query lands, so the genuine stale-selection case that
cascading dropdowns rely on still clears. A pending query that errored is
treated the same way, which is the conservative reading already documented
for the empty-result case: keeping a selection we cannot check beats
clearing one that was valid.

Dropdowns with no query at all are unaffected — there is no pending state,
so static options validate exactly as before.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Sep 4, 2026

Copy link
Copy Markdown

@alecrt is attempting to deploy a commit to the Evidence Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant