Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Dynamic Options Select Form Block for Solid

A join-a-team form whose team select loads after a department is chosen, with skeleton rows while it loads, a failure with Retry, and an empty state for a department with no teams.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Handle options that arrive late with this dynamic options form for Solid with Ark UI. A compact header sits over a hairline frame with a plus mark on each corner: two cells on one hairline, Department and Team, and a band under them that lists the teams. Choosing a department starts a 700 ms simulated load: the team Select reads "Loading teams" and is marked busy, and the band shows Skeleton rows with a spinner in its count. Legal fails the first time ("Could not load the teams in Legal." with a Retry that works), Facilities has no teams and shows an Empty state, and the other departments list their teams with a one-line description and head count. A response for a department you left is dropped, so switching quickly never shows the wrong list. Joining before the teams are ready says why. It's built from Select, Skeleton, Empty, Field, Button, Shine Button and Guides. For directories, pickers that call an API and any list that depends on a server.

FAQ

How does it ignore a response that arrives late?

Each load is a timer started by an effect that depends on the department and the attempt, and the effect's cleanup clears it. Choose another department while one is loading and the first timer never fires, so its result can never land on the second choice. With a real fetch, do the same with an AbortController aborted in the cleanup, or compare a request counter before you set the result.

How do I test the failure and the retry?

Choose Legal: its first load fails by script, the band shows the message and a Retry button, and the second load succeeds. The scripted failure is one line in outcomeOf; remove it, or return "error" for your own cases, when you connect a real request.

How does it work with a keyboard and a screen reader?

Both selects have labels and the team select is disabled until the teams are ready. The cell is marked aria-busy while loading, the foot (the one live region) says "Loading Engineering teams." and then how many loaded, and the skeleton rows are hidden from assistive technology. Retry is a real button, and a failed Join puts focus on the select that is missing.

How does it look on a phone?

The two cells stack with a rule between them. The list band has a fixed height, so the skeleton, the list, the error and the empty state all take the same space and nothing below them moves.

What stays local, and how do I connect it for real?

The departments and teams are typed constants, the delay is a timer and nothing is saved: the foot says "Joined in this demo. Nothing sent." In your app, replace the timer with a request for the department's teams and keep the same four states (loading, ready, empty, error); send the department and team on Join.

How do I connect it to react-hook-form or TanStack Form?

Keep the load in your data layer, such as a query keyed by the department, and keep only the chosen ids in the form. react-hook-form is a React library; use TanStack Form's adapter for your framework, with a listener on department that clears team.