React Has Separation of Concerns, Just Not the One You Learned First
Traditional web dev taught one file per technology. React breaks that rule on purpose. The separation is still there, it just runs along a different line.
When I first saw JSX, my instinct was that something was wrong.
HTML inside JavaScript. CSS in the same file. Everything in one block.
Everything I had been taught about separation of concerns said this was a mistake.
It is not a mistake. It is a deliberate architectural decision. Understanding it changed how I think about components entirely.
What "Separation of Concerns" Actually Meant
The rule we all learned: one file per technology. HTML for structure. CSS for presentation. JavaScript for behavior.
That made sense when JavaScript was a thin layer of interactivity sprinkled on top of server-rendered pages. A form that validates on submit. A dropdown that opens on click.
In those cases, HTML and JavaScript barely touched each other. Keeping them separate was natural.
But then SPAs happened.
The Moment the Old Rule Broke
As applications got more interactive, JavaScript stopped being a sprinkle and became the engine. The HTML on the screen stopped being written in a template. It started being generated and managed entirely by JavaScript. Every element on the page became JavaScript's responsibility.
At that point, the separation was already gone.
The HTML did not make sense without the JavaScript. The JavaScript could not do anything without the HTML it was managing. They were tightly coupled whether the files were separate or not.
Keeping them in separate files just made that coupling harder to follow.
Co-location: Things That Change Together Should Live Together
This is the principle React was built around.
If a piece of JavaScript controls a piece of HTML, those two things should be close to each other. Not because it looks clean, but because when the logic changes, the markup needs to change too. When the markup changes, the logic needs to change too.
Splitting them across files means every change requires hunting in two places.
Co-location is not laziness. It is reducing the distance between things that are coupled.
React's answer was the component: a single unit that contains the data, the logic, and the appearance for one piece of the UI. All three concerns, together, because all three change for the same reasons.
The Separation Is Still There
React does not throw separation of concerns out the window.
It moves the separation boundary.
Traditional web dev separated by technology: one HTML file, one CSS file, one JS file. React separates by feature: one component per piece of the UI.
Traditional: React:
──────────────── ────────────────────────────
HTML file <CartWidget>
everything cart count logic
CSS file cart count markup
everything cart count styles
JS file </CartWidget>
everything
<CheckoutButton>
button logic
button markup
button styles
</CheckoutButton>Each component is only concerned with one thing. That is still separation of concerns. It is just not one concern per file. It is one concern per component.
ExpandDiagram showing traditional separation (one file per technology) on the left versus React component-based separation (one file per UI concern) on the right.
Why This Actually Works Better
The old rule assumed that "HTML things" and "JavaScript things" are naturally separate concerns.
They are not. Not anymore. A button's appearance and a button's behavior are one concern: the button. The nav's structure and the nav's state are one concern: the nav.
When you work on the cart feature, you open the cart component. Everything you need is there. You do not split attention across three files that happen to share a feature boundary.
The component is the concern.
This is why React and virtually every modern frontend framework converged on components as the unit of organization. It was not a design preference. It was the natural conclusion of how JavaScript-heavy applications actually work.
The Essentials
- Traditional separation of concerns (one file per technology) made sense when JavaScript was a thin layer on top of server-rendered HTML. It stopped making sense when JavaScript started controlling the UI.
- Co-location is the principle behind JSX: things that change together should live close together. The logic and the markup for a component change for the same reasons, so they belong in the same place.
- React still has separation of concerns. It just separates by component (one concern per piece of the UI) instead of by technology (one concern per file).
Further Reading and Watching
- React in 100 Seconds -- Fireship: A fast visual overview of the component model and how JSX fits in.
- Thinking in React -- React Docs: The official guide to the mental model behind React's component and state design.
Keep reading