How to Display a Dropdown Selection in Another Element

Beginner8 min interview
Skills tested:
Making a select element controlled with value from state and onChange updating stateDisplaying the same state value in multiple locations simultaneouslyDistinguishing between the option value (what is stored) and the option label (what is displayed)Looking up the full object from an ID-based select stateBuilding a confirmation or summary panel that reflects form selections in real time

Advertisement

🧩 Scenario

Displaying a form selection elsewhere on the page appears in confirmation panels, live preview cards, summary bars, and multi-step form reviews. It is the same controlled component principle as display-user-input but applied to a select element. Once the value is in state, rendering it anywhere is just referencing the same variable.

Architecture Walkthrough

The Same State, Multiple Displays

The core insight is that once a value is in React state, it can be displayed anywhere in the same component tree without any extra synchronization. A controlled select stores its current value in state. Any JSX that references that state variable automatically reflects the latest selection on every render.

This is not a special pattern for dropdowns. It is the same principle as the controlled input mirror: React state is the single source of truth, and the UI is a projection of that state. Multiple elements can read from the same state simultaneously.

Value vs Label

When dropdown options are objects with distinct id and name fields, the controlled value on the select stores the id (a string from e.target.value). If you need to display the human-readable label elsewhere, you look it up from the original array: options.find(o => String(o.id) === selectedId)?.name. Never store the full object in state via the select because e.target.value only gives you the string value of the <option> element.


Key Code Explained

// Simple string array: value = label = same string
const LANGUAGES = ['TypeScript', 'Python', 'Rust', 'Go'] as const;
type Language = (typeof LANGUAGES)[number];

function LanguageMirror() {
  const [selected, setSelected] = useState<Language | ''>('');

  return (
    <div>
      <select
        value={selected}
        onChange={(e) => setSelected(e.target.value as Language)}
      >
        <option value="" disabled>Select a language...</option>
        {LANGUAGES.map((lang) => (
          <option key={lang} value={lang}>{lang}</option>
        ))}
      </select>

      {/* Display the same state in multiple places */}
      <input
        type="text"
        value={selected || ''}
        readOnly
        placeholder="Your selection will appear here"
      />

      {selected && (
        <p>You selected: <strong>{selected}</strong></p>
      )}
    </div>
  );
}


// Object array: store ID, look up label for display
interface Plan {
  id: number;
  name: string;
  price: number;
  features: string[];
}

const PLANS: Plan[] = [
  { id: 1, name: 'Free', price: 0, features: ['5 projects', '1 GB storage'] },
  { id: 2, name: 'Pro', price: 29, features: ['Unlimited projects', '100 GB storage', 'Priority support'] },
  { id: 3, name: 'Enterprise', price: 99, features: ['Custom limits', 'SLA', 'Dedicated account manager'] },
];

function PlanSelector() {
  const [selectedId, setSelectedId] = useState<number | null>(null);

  // Derived from state — look up the full object when needed
  const selectedPlan = PLANS.find((p) => p.id === selectedId);

  const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const id = parseInt(e.target.value, 10);
    setSelectedId(isNaN(id) ? null : id);
  };

  return (
    <div className="plan-selector">
      <div className="selector-column">
        <label htmlFor="plan-select">Choose a plan</label>
        <select id="plan-select" value={selectedId ?? ''} onChange={handleChange}>
          <option value="" disabled>Select plan...</option>
          {PLANS.map((plan) => (
            <option key={plan.id} value={plan.id}>{plan.name}</option>
          ))}
        </select>
      </div>

      {/* Summary panel: derives everything from the same selectedId state */}
      {selectedPlan ? (
        <div className="plan-summary">
          <h3>{selectedPlan.name}</h3>
          <p className="price">${selectedPlan.price}/month</p>
          <ul>
            {selectedPlan.features.map((f) => (
              <li key={f}>{f}</li>
            ))}
          </ul>
        </div>
      ) : (
        <div className="plan-summary plan-summary-empty">
          <p>Select a plan to see details</p>
        </div>
      )}
    </div>
  );
}


// Multi-select summary: three selects, one summary row
function OrderSummary() {
  const [size, setSize] = useState('');
  const [color, setColor] = useState('');
  const [quantity, setQuantity] = useState('1');

  const isComplete = size && color && quantity;

  return (
    <div>
      <div className="selectors">
        <select value={size} onChange={(e) => setSize(e.target.value)}>
          <option value="" disabled>Size</option>
          {['S', 'M', 'L', 'XL'].map((s) => <option key={s} value={s}>{s}</option>)}
        </select>

        <select value={color} onChange={(e) => setColor(e.target.value)}>
          <option value="" disabled>Color</option>
          {['Black', 'White', 'Navy'].map((c) => <option key={c} value={c}>{c}</option>)}
        </select>

        <select value={quantity} onChange={(e) => setQuantity(e.target.value)}>
          {[1, 2, 3, 4, 5].map((q) => <option key={q} value={q}>{q}</option>)}
        </select>
      </div>

      {/* Summary derived from three state variables simultaneously */}
      {isComplete && (
        <p className="summary">
          {quantity}x {color} ({size})
        </p>
      )}
    </div>
  );
}

In PlanSelector, selectedPlan is derived during render from selectedId. No useEffect is needed to keep the plan in sync; every time selectedId changes, React re-renders and selectedPlan is recomputed. Storing the full plan object in a separate state variable and updating it with useEffect would be the derived state anti-pattern.


Tradeoffs

Display locationMechanismSync required
Same componentReference state variable directlyNone
Child componentPass as propNone
Sibling componentLift state to common ancestorNone
Global (unrelated)Context or state managerNone (reactive)

What Interviewers Actually Check

  • Whether you use a controlled select with value and onChange
  • Whether you reference the same state variable to display it elsewhere (not a separate effect)
  • Whether you handle the no-selection case in the display element
  • Whether you can look up a label from an object array when the state stores an ID
  • Whether you know derived state (computing selectedPlan in render) vs stored state anti-pattern

Follow-Up Questions

  1. How would you display the selected plan in a completely separate component not in the same tree, without prop drilling?
  2. How does useMemo apply to the selectedPlan derivation if the PLANS array were expensive to search?
  3. How would you animate the summary panel appearance when a plan is first selected, using Framer Motion?
  4. How would you persist the selected plan ID in the URL so the user can share a link with the plan pre-selected?
  5. How would you build a comparison view where the user selects two plans and sees them side by side?

Common Candidate Mistakes

  • Not making the select controlled, relying on ref to read the value on submit, which means the summary panel cannot update in real time
  • Trying to store the full selected object in state via e.target.value, which only gives the string value, not the object
  • Using a useEffect to sync selected value to a separate display state, creating unnecessary derived state
  • Not handling the empty state of the display element, leaving undefined or an empty string visible
  • Making the display <input> editable instead of readOnly, allowing the user to modify it without it affecting the select

Interview Readiness Checklist

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

  • Can you make a controlled <select> and display its selected value in a separate element?
  • Can you look up the full object label from an array when the select state stores an ID?
  • Can you handle the no-selection state gracefully in all display elements?
  • Can you build a live summary panel that reflects multiple dropdown selections simultaneously?
  • Can you explain why deriving display values during render is better than syncing them in useEffect?

Summary

Displaying a dropdown selection elsewhere on the page is a direct application of the controlled component pattern. The select stores its value in state with value and onChange. Once the value is in state, any JSX in the same component can reference it by reading the same state variable. No synchronization or useEffect is needed: React re-renders the component on every state change, and all elements that read from that state reflect the new value automatically.

When the options are objects with distinct id and label fields, the select stores the id (a string from e.target.value). To display the human-readable label, look up the object from the original array during render: options.find(o => String(o.id) === selectedId). This is derived state computed during render, not stored state in a separate useState. Computing display values during render keeps the state minimal and avoids the derived state anti-pattern.

For complex forms with multiple selections feeding a summary panel, the same principle scales: each select owns its own state variable, and the summary panel reads from all of them simultaneously. Everything stays in sync automatically because React re-renders the whole component on any state change.

Frequently Asked Questions

How do I display the label of the selected option when the value is an ID?

Store the ID as the controlled value. To get the label, look up the option in the original array using find(): options.find(o => o.id === selectedId)?.label

Advertisement


Stay Updated

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

Advertisement