Step 4 — Replace a Component
Goal
Apply the module to code you own, and produce a defensible decision either way.
The exercise
Pick one component from a codebase you work on:
| If you have… | Native primitive |
|---|---|
| custom modal | <dialog> + showModal() |
| custom dropdown / menu | popover + popovertarget, or <select> |
| custom accordion | <details> / <summary> |
| custom tooltip | popover + CSS anchor positioning |
| custom checkbox/radio | real <input> + appearance: none |
| custom progress / meter | <progress> / <meter> |
1. Measure the current one
Run it through the experiment-2 behaviour table. Do not read the code — test it:
- Does focus move in when it opens?
- Press Tab 10 times: does focus escape?
- Does Escape close it?
- Is focus restored to the trigger?
- Can you reach the background while it is open?
- Does it work with Enter and Space?
Record JS bytes for the component and its dependencies.
2. Build the native version
Same visual result. Measure the same table and the same bytes.
3. Decide, and write it down
Either outcome is a pass. What is required is the reasoning:
If you replace it: what did you lose? Usually specific styling. Is there a platform answer
(::backdrop, ::part(), appearance, anchor positioning)?
If you keep the custom one: name every native behaviour you are now responsible for maintaining, and say what test proves each still works. If no test proves it, that is the finding — write the tests before writing the justification.
Deliverable
## Component: <name>
Current: <element>, <N> bytes JS, behaviour table <X>/7
Native: <element>, <M> bytes JS, behaviour table <Y>/7
Lost by switching:
Platform answer (if any):
Decision:
If keeping custom — behaviours I now own, and the test that proves each:
Why this step exists
The measurements in steps 1–3 are persuasive and belong to someone else's code. This step is where the module either transfers or does not. It is also the exercise that most often surfaces an uncomfortable result: the custom component fails behaviours nobody knew it failed, because nobody had ever tested it with a keyboard.
Checkpoint
docs/verification.md Checkpoint 6.