Quick take: Fine-grained reactivity, HTML over the wire, and utility-first CSS are all second or third runs of ideas that were mainstream years earlier. That is not a criticism. The useful move is to ask which constraint changed between the two runs. If a specific limit was removed (Proxy landing in ES2015, HTTP/2 multiplexing, native CSS nesting), the return is technical. If nobody can name one, it is fashion, and it will leave the same way it did last time.
I've been writing code for the web since the mid-nineties, and the strangest part of a long run isn't watching things change. It's watching them come back. Not similar things. The same thing, with a different name, argued by people who are certain it's new, sometimes with the exact objections from the previous round repeated as fresh insight.
That sounds like a complaint. It isn't one. Why would a rerun be bad news? A returning idea is the single most useful thing you can be handed, because the first run already generated years of production evidence about what the idea costs. You just have to know you're looking at a rerun.
Loop One: Fine-Grained Reactivity Became Signals
Knockout.js was released on 5 July 2010 by Steve Sanderson. Its core primitive was the observable: a value you read through a function call, which tracks who read it and re-runs exactly those readers when it changes. No diffing. No component re-render. The pattern came from MVVM, which .NET developers already knew from WPF and Silverlight.
Read that description again and tell me it isn't a signal. It is a signal, down to the dependency tracking.
Then Knockout lost, mostly to AngularJS and then to React, and the industry spent roughly a decade with a different model: re-run the component, diff the output, patch the DOM. Fine-grained reactivity became a thing old people mentioned.
Then it came back, and quickly:
| Release | Date | What it called the idea |
|---|---|---|
| Knockout, initial release | 5 July 2010 | Observables |
| Mobservable, renamed MobX in 2016 | 2015 | Observables |
| Solid 1.0 | 28 June 2021 | Signals |
| Preact Signals | 6 September 2022 | Signals |
| Angular v16 | May 2023 | Signals (developer preview) |
| TC39 proposal | 2024 | Signals (Stage 1) |
So what actually changed? Three things, and all three are nameable. Proxy shipped in ES2015, which removed the need to wrap every value in an explicit observable() call and made the ergonomics tolerable. Compilers got good enough to rewrite template code, so the reactivity graph could be built at build time rather than assembled by hand. And by around 2020 there was enough production telemetry to argue that re-render-and-diff has a real cost at scale, rather than a theoretical one.
Three named constraints, all removed. That's what a legitimate return looks like.
Loop Two: HTML Over the Wire Never Actually Left
The web started by sending HTML. Then it sent HTML with a bit of script. Then, for about a decade, the respectable answer was to send JSON and build the HTML in the browser, and anything else was legacy.
I spent a long stretch of my career in PHP, which is where most of the working web genuinely lived while frontend conferences pretended otherwise. The model there was simple: the server owns the markup, the browser renders it. When single-page applications arrived, that model wasn't refuted, it was declared unfashionable.
Look at what came back. Carson Gross started intercooler.js in 2013 to do partial updates with HTML attributes; he rewrote it without the jQuery dependency and released it as htmx on 24 November 2020. Rails shipped Turbo the same year. And React announced zero-bundle-size Server Components on 21 December 2020, taking four years to reach stable in React 19 on 5 December 2024.
Three separate projects, three separate communities, one idea: the server produces markup, the client swaps it in.
The constraint that changed is HTTP. Under HTTP/1.1 with six connections per host, chatty partial updates were genuinely expensive, which is a large part of why bundling everything into one payload won. Multiplexing and streaming responses removed that penalty. If you want the implementation detail rather than the history, React Server Components in TypeScript covers the current shape of it.
Is the returning version identical? No, and that matters. Server Components stream a serialized component tree rather than raw markup, and they compose with client components in a way intercooler never attempted. The idea returned; the implementation learned something.
Loop Three: The Styling Pendulum Keeps Swinging Back
This one is the clearest, because the swings are documented.
Global stylesheets came first, and their problem was always the same: no scoping. Thierry Koblentz argued the utility-class answer publicly in Smashing Magazine in October 2013, under the name atomic CSS, and got roundly told it was inline styles with extra steps. CSS Modules took the scoping route in 2015. styled-components took the runtime route in 2016. Tailwind shipped its first public alpha on 1 November 2017 and won the argument Koblentz had lost four years earlier with substantially the same technique.
Then the pendulum moved again. styled-components entered maintenance mode on 17 March 2025, with its maintainer saying outright that he wouldn't recommend it for new projects. Meanwhile the browser grew the features the libraries existed to supply: native CSS nesting versus Sass is now a real comparison rather than a joke, cascade layers give you the ordering control that specificity wars used to need, and container queries solved component-scoped responsiveness without a JavaScript runtime.
Notice the pattern. Every styling library of the last fifteen years was a polyfill for something the platform lacked. So what's left once the platform ships that thing? Ergonomics, and ergonomics alone doesn't survive a maintainer burning out.
How Long the Gaps Actually Are
Four to eleven years. That's short enough that the people who lived through the first run are still working, and long enough that most of the room hasn't heard of it. Which is exactly why the reruns keep getting sold as debuts.
The Test This Gives You
One question, asked before adopting anything that feels new: which constraint changed?
A legitimate return names something specific and checkable:
- A browser API shipped (
Proxy, container queries, view transitions) - A protocol changed (HTTP/2 multiplexing, streaming responses)
- A compiler became viable where hand-writing wasn't
- A cost moved from theoretical to measured
A rebrand can't answer. It'll tell you about developer experience, or that the old version was "before its time", which is a sentence that means nothing. When I hear that phrase in a conference talk now, I stop taking notes.
The second question is cheaper and more useful: what killed it last time, and is that thing fixed? Knockout didn't die because observables were wrong. It died partly because writing observable() around everything was miserable, and Proxy fixed exactly that. If you can trace the fix, you're on solid ground. If the answer is that the old version was unfairly maligned, walk away.
The Prediction I'll Be Held To
Here's where you're welcome to disagree with me, and plenty of people do.
The returning idea almost never wins outright. It gets absorbed. Observables came back; Knockout didn't. HTML over the wire came back; nobody's rewriting their application in intercooler. Utility classes came back and then immediately started ceding ground to native CSS features.
So I'd bet against a signals-based core in React this decade. Not because signals are wrong, they're clearly good, and Solid and Angular have proved it. But React's value was never its reactivity model, it was the component contract that thousands of libraries were written against, and that contract is what makes a core rewrite unaffordable. React will absorb the parts it can and keep re-rendering. Which is roughly what jQuery did with its competitors' ideas for a decade after everyone announced it was finished.
Bet the other way if you like. Just make sure you can name the constraint that changed, because "everyone's excited about it" was also true in 2010, and it wasn't a reason then either. If you want the same lens applied to bundle weight rather than architecture, the three pillars of JavaScript bloat is the measured version of this argument.
The frontend doesn't move in a line. It moves in loops, and each loop returns with better tooling and the same trade-offs. Knowing which loop you're standing in is most of the skill.