Props Without Pain: Props Collection / Getter Pattern

Provide helper functions (getInputProps) that spread required props onto elements. This keeps your component flexible while hiding complexity. Perfect for libraries like Downshift that need rich APIs.

Ever been at a restaurant where the waiter brings out all condiments in one tray instead of making you ask for salt, pepper, ketchup, and chili separately?

That’s exactly what the Props Collection / Getter Pattern does in React — it bundles all the props you need into one neat package, so you don’t have to manually manage each piece every time.

Core Idea

The Props Collection Pattern provides a single object or function (getter) that returns all the props you need for a component.

👉 Instead of:

<input onChange={handleChange} value={value} aria-label="username" />

You get:

<input {...getInputProps()} />

Basics & Need

  • When building reusable components (inputs, buttons, modals), consumers often need lots of props.
  • Passing them one by one is error-prone and verbose.
  • The Props Getter pattern provides a preconfigured props object (often via a function) that consumers can spread onto their components.

How to Achieve It

Example 1: Basic Props Getter

const useInput = () => {
const [value, setValue] = React.useState("");

const getInputProps = (props = {}) => ({
value,
onChange: (e) => setValue(e.target.value),
...props, // allow overrides
});

return { value, getInputProps };
};

// Usage
const UsernameField = () => {
const { value, getInputProps } = useInput();

return (
<>
<input {...getInputProps({ placeholder: "Enter username" })} />
<p>Value: {value}</p>
</>
);
};

👉 getInputProps ensures the consumer gets all required props, while still allowing customization.


Example 2: Multiple Props Collections (Input + Button)

const useToggle = () => {
const [on, setOn] = React.useState(false);

const getToggleProps = (props = {}) => ({
"aria-pressed": on,
onClick: () => setOn(!on),
...props,
});

return { on, getToggleProps };
};

// Usage
const Toggle = () => {
const { on, getToggleProps } = useToggle();

return (
<>
<button {...getToggleProps()}>{on ? "ON" : "OFF"}</button>
</>
);
};

Best Practices

✅ Use getters to bundle required behavior (like onChange, value).
✅ Allow consumers to override or extend props.
✅ Keep function naming clear (getInputProps, getToggleProps).
❌ Don’t overstuff getters with too many unrelated props.

Real-World Examples

  1. Forms (Formik, React Hook Form) → Inputs come pre-bundled with handlers and values.
  2. Toggle Switches → Provides accessibility props + event handlers.
  3. UI Libraries (Downshift, Headless UI) → Consumers spread getters for inputs, menus, buttons.

Advantages

✔ Cleaner API for consumers.
✔ Reduces prop drilling and mistakes.
✔ Supports overrides and extensions.
✔ Enhances accessibility by including ARIA props.

Disadvantages

⚠ May hide complexity from beginners.
⚠ Debugging is harder when props come from a single getter.
⚠ Overuse can lead to unintuitive APIs.

Common Problems / Pitfalls

  • Forgetting to spread props ({...getInputProps()}) → component breaks.
  • Overwriting internal props (like onChange) without merging.
  • Poorly documented getters confuse consumers.

Summary Recommendation

🎯 Use the Props Getter Pattern to simplify component APIs by bundling required props into a getter function. Perfect for forms, toggles, dropdowns, and UI libraries where components need multiple props consistently. Keep APIs clean, flexible, and override-friendly.