How to Bind an Array to a Dropdown in React

Beginner8 min interview
Skills tested:
Rendering option elements from an array using map()Making a controlled select with value from state and onChange updating stateUsing object arrays with distinct value and label fieldsAdding a default placeholder option that prompts the user to selectHandling the case where the selected value is an object ID that needs to be used elsewhere

Advertisement

🧩 Scenario

Binding an array to a dropdown is a ubiquitous form pattern: country selectors, role selectors, category filters, plan pickers. It combines two skills: list rendering with map() and the controlled select pattern. The selected value drives subsequent logic, so knowing how to read it from state correctly matters.

Architecture Walkthrough

Rendering Options with map()

A <select> dropdown requires each choice to be an <option> element. To build these dynamically from an array, map() over the data and return an <option> for each item. Each <option> needs a key prop (for React's reconciliation), a value prop (what gets submitted or read from e.target.value), and display text between the tags.

For an array of strings, the string itself works as both the key and the value. For an array of objects, the object ID is the value (what you track in state) and the name or label is the display text.

Making It Controlled

An uncontrolled select lets the browser manage the selected state, which makes it hard to read programmatically or synchronize with other UI. A controlled select sets value={selectedValue} on the <select> element and updates state with onChange={(e) => setSelectedValue(e.target.value)}. The same state variable can then be used anywhere: passed to an API call, used to filter another list, or shown in a summary.

e.target.value is always a string, even when the array values are numbers. If your IDs are numbers, parse the value: Number(e.target.value) or parseInt(e.target.value, 10).

Placeholder Option

A disabled, empty-value first option serves as a visual prompt ("Select a country"). Set its value to an empty string and mark it disabled to prevent reselection after a real option is chosen. Check if (!selectedValue) to know when nothing has been selected yet.


Key Code Explained

// Array of strings
const ROLES = ['Admin', 'Editor', 'Viewer'] as const;
type Role = (typeof ROLES)[number];

function RoleSelect({ onRoleChange }: { onRoleChange: (role: Role) => void }) {
  const [role, setRole] = useState<Role | ''>('');

  const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const value = e.target.value as Role;
    setRole(value);
    if (value) onRoleChange(value);
  };

  return (
    <select value={role} onChange={handleChange}>
      <option value="" disabled>Select a role...</option>
      {ROLES.map((r) => (
        <option key={r} value={r}>{r}</option>
      ))}
    </select>
  );
}


// Array of objects with id and label
interface Country {
  code: string; // 'IN', 'US', 'DE'
  name: string; // 'India', 'United States', 'Germany'
}

function CountrySelect({
  countries,
  onSelect,
}: {
  countries: Country[];
  onSelect: (code: string) => void;
}) {
  const [selectedCode, setSelectedCode] = useState('');

  const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const code = e.target.value;
    setSelectedCode(code);
    onSelect(code);
  };

  return (
    <div>
      <label htmlFor="country-select">Country</label>
      <select id="country-select" value={selectedCode} onChange={handleChange}>
        <option value="" disabled>Select a country...</option>
        {countries.map((country) => (
          <option key={country.code} value={country.code}>
            {country.name}
          </option>
        ))}
      </select>

      {selectedCode && (
        <p>Selected: {countries.find((c) => c.code === selectedCode)?.name}</p>
      )}
    </div>
  );
}


// Numeric IDs: convert e.target.value from string to number
interface Plan {
  id: number;
  name: string;
  price: number;
}

function PlanSelect({ plans }: { plans: Plan[] }) {
  const [selectedPlanId, setSelectedPlanId] = useState<number | null>(null);
  const selectedPlan = plans.find((p) => p.id === selectedPlanId);

  const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    // e.target.value is always a string — parse to number
    const id = parseInt(e.target.value, 10);
    setSelectedPlanId(id);
  };

  return (
    <div>
      <select
        value={selectedPlanId ?? ''}
        onChange={handleChange}
      >
        <option value="" disabled>Choose a plan...</option>
        {plans.map((plan) => (
          <option key={plan.id} value={plan.id}>
            {plan.name} - ${plan.price}/mo
          </option>
        ))}
      </select>

      {selectedPlan && <p>You selected: {selectedPlan.name}</p>}
    </div>
  );
}

In PlanSelect, value={selectedPlanId ?? ''} handles the null initial state by falling back to an empty string, which matches the placeholder option's value. Without this, the <select> would receive null as its value, which React coerces to the string "null" and matches no option, leaving the browser to display the first option instead of the placeholder.


Tradeoffs

PatternControlledValue typeUse when
String arrayYesstringSimple choices with no separate ID
Object arrayYesstring (ID)Data from API with distinct value and label
Numeric ID objectYesnumber (parsed)API IDs are numbers, not strings

What Interviewers Actually Check

  • Whether you make the select controlled with value and onChange
  • Whether you use a stable object ID as the option key and value
  • Whether you add a placeholder option for "no selection yet"
  • Whether you know e.target.value is always a string and can convert it
  • Whether you can look up the full object from the selected ID when needed

Follow-Up Questions

  1. How would you implement a multi-select dropdown where the user can choose multiple values simultaneously?
  2. How would you use react-select or a similar library for a searchable dropdown with thousands of options?
  3. How would you build a dependent dropdown where selecting a country loads its states from an API?
  4. How does react-hook-form's Controller component handle a controlled <select> with Zod validation?
  5. How would you reset the dropdown to its placeholder state when a parent filter changes?

Common Candidate Mistakes

  • Not making the select controlled, leaving the browser to manage selection state and making it hard to read the value programmatically
  • Using array index as the option key, which breaks when the options array is filtered or reordered
  • Not adding a disabled placeholder option, making it ambiguous whether the user has made a selection
  • Not knowing that e.target.value is a string and passing it as a number ID to an API call that expects a number
  • Trying to store the entire selected object in state via e.target.value, which only gives the string value of the selected option

Interview Readiness Checklist

Before you leave this question, make sure you can answer:

  • Can you render a controlled select from an array of strings?
  • Can you render a controlled select from an array of objects with distinct ID and display label?
  • Can you add a disabled placeholder option and detect when no real selection has been made?
  • Can you explain why e.target.value is always a string and how to convert it to a number?
  • Can you look up the full object from the selected ID when you need more than the ID?

Summary

Binding an array to a dropdown combines list rendering and the controlled component pattern. Use map() over the array to produce <option> elements with a key (the stable ID), a value (what gets stored in state), and display text. The <select> itself is controlled with value={selectedValue} and onChange updating state.

For arrays of objects, the value on each <option> is the object ID (a string or number serialized to a string), and the display text is the human-readable name. When you need the full object, look it up from the array using find() with the selected ID. e.target.value is always a string; convert it with parseInt or Number() when your IDs are numeric.

Always add a disabled, empty-value placeholder option as the first <option> to prompt the user to make a selection. Without it, the first real option appears selected on initial render even when no selection has been made, and validation that requires a choice becomes ambiguous.

Related Videos
Watch these videos to learn more about this topic
Frequently Asked Questions

How do I know which option the user selected?

Use a controlled select with value={selectedValue} and onChange={(e) => setSelectedValue(e.target.value)}. The e.target.value string gives you the value of the selected option.

Advertisement


Stay Updated

Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.

Advertisement