Keep Implementation Private In short: If nobody can see inside a component, you can replace everything inside it. Privacy is not about hiding — it is about buying yourself the right to change your mind. The previous lesson locked the front door. This one is about why that lock is worth having. Hiding internals protects consumers from coupling to things that will change. That is the defensive reason, and it is the one usually given. The better reason is offensive: a component whose internals nobody can see is a component you are free to rewrite. The freedom to rewrite Multiple apps in the dairy platform need a process tracker. Tanker intake tracks a truck: arrived → weighing → unloading . Lab testing tracks a sample: drawn → testing → graded . You build . Version 1: ship something You need it this sprint, so it is a with flexbox. Two exports. That is the entire promise. Version 2: the redesign A year later, design wants animated SVG connectors, branching paths, and sub-steps. A will not do it. You need internal child components and a layout service. The DOM structure changed completely. The rendering technology changed from HTML to SVG. There is a new service and two new components. The public API did not move. is byte-for-byte identical. Consumers run , get animated steppers, and change nothing. They never learn that the internals were replaced — which is exactly the outcome you want. What privacy actually protects Three specific things become free to change once nobody can reach them: Free to change Because consumers cannot… --- --- DOM structure …target it with CSS (encapsulation + no ) Internal child components …import them (not in ) Internal services …inject them (not exported, provided on the component) CSS class names …select them (they are implementation, not contract) The rendering approach entirely …depend on any of the above Note that is provided on the component, not . Even if someone found the class, they could not inject it outside the stepper. Scope is a privacy mechanism as much as a lifetime one. The three leaks Privacy fails in three ways, and only one of them is about exports. 1. The export leak — covered in the previous lesson. An internal in . 2. The CSS leak. A consumer uses to reach a class name inside your component. Your class names are now a contract you never agreed to, and renaming breaks them. Chapter 6 deals with this properly; the short version is that you expose CSS custom properties as the supported customisation channel, and internal class names stay internal. 3. The type leak. This one is subtle: Even though is not in , consumers can now name it with and write code against its shape. Public signatures should only mention public types. Where the boundary genuinely is The line is not "what did I export". It is what did a consumer observe . If consumers can see it, it is a contract whether you meant it or not: Observable to consumers → contract Invisible → yours --- --- Input and output names and types Internal component names What is rendered, and its accessible roles The DOM tree that produces it CSS custom properties you documented Internal CSS class names Emitted event payloads How the event is produced The component's rough visual footprint The layout technique used That third row on the left is the one people underestimate: once you document , renaming it is a breaking change, exactly like renaming an input. Chapter 9 treats it that way. "But I thought hiding internals just made the library less flexible" This is a real trade-off and the frustration behind it is legitimate. A consumer has a genuine need, your component almost does it, and the only thing standing between them and shipping is a you added. From their seat it looks like gatekeeping. But look at what "flexible" costs when it means "reachable". Consider the two paths after a consumer needs the stepper's nodes rendered slightly differently. The library is open. They import and compose their own variant. It works today. It is not flexibility — it is a fork with a shared dependency . They now depend on 's inputs, its DOM, and its CSS. Your Version 2 rewrite deletes that component. Their app breaks, they file a P1, and you learn about the coupling from the incident channel. The library is closed. They cannot do it, so they ask. Now one of three good things happens: you discover a genuine gap and add a supported input; you find they wanted a different component; or you realise the need is domain-specific and belongs in their feature. Every one of those outcomes is better than the fork, including the one where you say no. The reframing that makes this stick: privacy is not a restriction on consumers, it is a restriction on yourself. A closed component means you promised less, and the promises you did make you can actually keep. An open one means you promised everything, silently, and will break some of it. Open internals Private internals --- --- --- Consumer solves an edge case today Yes, immediately No — they ask…