Architecture Patterns

Preview — 3 of 10 questions

What is the Headless UI pattern?

javascript
// Headless: behavior + accessibility only, zero styling:
function useCombobox({ items, onSelect }) {
  const [isOpen, setIsOpen] = useState(false);
  const [query, setQuery] = useState("");
  const [highlighted, setHighlighted] = useState(0);
  const inputRef = useRef(null);

  const filtered = items.filter(i => i.label.toLowerCase().includes(query.toLowerCase()));

  const getInputProps = () => ({
    ref: inputRef,
    value: query,
    onChange: (e) => setQuery(e.target.value),
    onKeyDown: (e) => {
      if (e.key === "ArrowDown") setHighlighted(h => Math.min(h + 1, filtered.length - 1));
      if (e.key === "Enter") { onSelect(filtered[highlighted]); setIsOpen(false); }
    },
    "aria-expanded": isOpen,
    "aria-autocomplete": "list",
    role: "combobox",
  });

  return { isOpen, filtered, highlighted, getInputProps };
}

// Consumer provides full styling:
function StyledCombobox({ items }) {
  const { isOpen, filtered, getInputProps } = useCombobox({ items });
  return (
    <div className="my-company-combobox-styles">
      <input {...getInputProps()} className="rounded-md border-2 border-blue-500" />
      {isOpen && <ul>{filtered.map(i => <li>{i.label}</li>)}</ul>}
    </div>
  );
}
AHeadless components include default styling that can be overridden
BHeadless components provide behavior, state, and accessibility without any visual styling — consumers implement all CSS; enables the same logic to support any design system
CHeadless components are less accessible than styled components
DHeadless patterns require Web Components API

How does IoC manifest in React component design?

javascript
// LOW inversion of control — component makes all decisions:
function Autocomplete({ items, onSelect, allowNew, maxItems, filterFn, sortFn }) {
  // component controls everything
  const results = sortFn(filterFn(items)).slice(0, maxItems);
  return <List items={results} onSelect={onSelect} />;
}
// ← prop API explodes with every new use case

// HIGH inversion of control — consumer controls:
function Autocomplete({ items, children, onSelect }) {
  const [query, setQuery] = useState("");
  return children({ items, query, setQuery, onSelect });
}

<Autocomplete items={allItems} onSelect={handleSelect}>
  {({ items, query, setQuery }) => (
    <div>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      {items
        .filter(i => i.includes(query))
        .sort(customSort)
        .slice(0, 5)
        .map(i => <Option key={i} value={i} />)
      }
    </div>
  )}
</Autocomplete>
AHigher inversion of control always means a better API
BIoC trades API simplicity for flexibility — high IoC gives consumers full control but requires more code at usage sites; low IoC is simpler for common cases; good library design offers both (default behavior + escape hatches)
CInversion of control is only applicable to backend patterns
DThe render prop approach is the only way to implement IoC in React

How do you architect a multi-step form?

javascript
const STEPS = ["personal", "address", "payment", "review"] as const;
type Step = typeof STEPS[number];

function useWizard(steps: readonly Step[]) {
  const [currentStep, setCurrentStep] = useState<Step>(steps[0]);
  const [formData, setFormData] = useState<Partial<FormData>>({});

  const currentIndex = steps.indexOf(currentStep);

  const next = (stepData: Partial<FormData>) => {
    setFormData(prev => ({ ...prev, ...stepData }));
    if (currentIndex < steps.length - 1) setCurrentStep(steps[currentIndex + 1]);
  };

  const back = () => {
    if (currentIndex > 0) setCurrentStep(steps[currentIndex - 1]);
  };

  return { currentStep, formData, next, back, isFirst: currentIndex === 0, isLast: currentIndex === steps.length - 1 };
}
AA wizard should centralize form data at the orchestrator level — each step receives current data and a next(stepData) callback; accumulated data is passed to all steps; submission only happens from the final step
BEach step should manage its own global state independently
CMulti-step forms require URL routing for each step
DEach step must validate all previous steps before proceeding

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.