Once Upon a Time, Chaos Reigned in Front-End Development
The front-end world has been ruled by frameworks that promised you freedom:
- React, the "build anything, but at what cost?" framework.
- Vue, the "everything is kinda okay but just try to reuse your logic, I dare you" framework.
- Svelte, the "we’re simple until you need inheritance, then good luck" framework.
For years, developers convinced themselves these tools were the pinnacle of modern engineering. But behind the promises of "flexibility" and "developer experience" lurked frustration, duplication, and tears.
The Challenge: A Button with a Dropdown
Let’s test these frameworks—and Neuer—on a simple task:
A button with a dropdown.
The Use Cases:
- Version 1: Create a button with a dropdown.
- Version 2: Customize the dropdown’s content.
- Version 3: Override the click behavior.
- Version 4: Change styles to match a new context.
Sounds easy, right? Watch the big three fall apart. 🎭
React: A Render Function and a Prayer
React devs, gather ‘round. Here’s your React-based dropdown:
const DropdownButton = () => {
const [open, setOpen] = React.useState(false);
return (
<div className="dropdown">
<button className="btn" onClick={() => setOpen(!open)}>
Click Me <span className="caret"></span>
</button>
<div className={`dropdown-content ${open ? "show" : ""}`}>
Dropdown content
</div>
</div>
);
};
At first glance:
"Wow, React is so clean! Look at that JSX!"
But now let’s tweak it.
Version 2: Customize Dropdown Content
React says: "Time to rewrite everything!"
const CustomDropdownButton = () => {
const [open, setOpen] = React.useState(false);
return (
<div className="dropdown">
<button className="btn" onClick={() => setOpen(!open)}>
Click Me <span className="caret"></span>
</button>
<div className={`dropdown-content custom-style`}>
Totally custom content!
</div>
</div>
);
};
Duplicated logic, duplicated state.
Hope you remembered to copy the setOpen
function, or you’ll break everything. 🙃
Version 3: Override the Click Behavior
React says: "Sure, but you’ll need to rewrite the whole component again."
const CustomClickDropdown = () => {
const [open, setOpen] = React.useState(false);
const customToggle = () => console.log("Custom click logic!");
return (
<div className="dropdown">
<button className="btn" onClick={customToggle}>
Click Me <span className="caret"></span>
</button>
<div className={`dropdown-content ${open ? "show" : ""}`}>Dropdown content</div>
</div>
);
};
Fun Fact: That setOpen
logic? Yeah, it’s gone now. Good luck handling state without rewriting it all. 😏
Version 4: Change Styles
React says: "Hope you enjoy inline styles or CSS modules!"
const StyledDropdownButton = () => {
const [open, setOpen] = React.useState(false);
return (
<div className="dropdown" style={{ backgroundColor: "lightblue" }}>
<button className="btn" onClick={() => setOpen(!open)}>
Click Me <span className="caret"></span>
</button>
<div className={`dropdown-content ${open ? "show" : ""}`}>Dropdown content</div>
</div>
);
};
Inline styles? Really? Are we in 2013? React: where modularity goes to die. 💀
Vue: Directives All Day, Every Day
Here’s Vue’s starting dropdown:
<template>
<div class="dropdown">
<button class="btn" @click="toggleDropdown">
Click Me <span class="caret"></span>
</button>
<div :class="['dropdown-content', { show: isOpen }]">Dropdown content</div>
</div>
</template>
<script>
export default {
data() {
return { isOpen: false };
},
methods: {
toggleDropdown() {
this.isOpen = !this.isOpen;
},
},
};
</script>
Looks nice! But let’s see the cracks.
Version 2: Customize Dropdown Content
Vue says: "Go ahead and duplicate everything."
<template>
<div class="dropdown">
<button class="btn" @click="toggleDropdown">
Click Me <span class="caret"></span>
</button>
<div class="dropdown-content custom-style">Totally custom content!</div>
</div>
</template>
<script>
export default {
data() {
return { isOpen: false };
},
methods: {
toggleDropdown() {
this.isOpen = !this.isOpen;
},
},
};
</script>
Another entire component for one small tweak. DRY? What’s that? 🥴
Version 3: Override the Click Behavior
Vue says: "Rewrite the methods section too, kid."
<script>
export default {
data() {
return { isOpen: false };
},
methods: {
toggleDropdown() {
console.log("Custom click logic!");
},
},
};
</script>
Your dropdown’s behavior is isolated from the base logic. Hope you don’t need to share any logic with other components.
Version 4: Change Styles
Vue says: "Scoped styles to the rescue!"
But you still need to copy the template and styles into a new file.
Svelte: Rewrite It All, Forever
In Svelte, you get simplicity… until you need to reuse or tweak something.
The Neuer Way: One Class to Rule Them All
Version 2: Customize Dropdown Content
Extend. Override get template
. Done.
export class CustomDropdown extends DropdownButton {
static {
this.registerElement();
}
get template() {
return `
<div class="dropdown">
<button class="btn" c-click="toggleDropdown">Click Me <span class="caret"></span></button>
<div class="dropdown-content custom-style">Totally custom!</div>
</div>
`;
}
}
Version 3: Override Click Behavior
Override one method. Done.
export class CustomClickDropdown extends DropdownButton {
static {
this.registerElement();
}
toggleDropdown() {
console.log("Custom click logic!");
}
}
Version 4: Change Styles
Tweak get styles
. Done.
export class StyledDropdown extends DropdownButton {
static {
this.registerElement();
}
get styles() {
return `
${super.styles}
.dropdown-content {
background-color: lightblue;
color: darkblue;
}
`;
}
}
The Moral of the Story
React makes you duplicate.
Vue makes you rewrite.
Svelte makes you start over.
Neuer? Makes you smile. 😏
Stop copying, pasting, and rewriting your life away. It’s time for a Neuer way of doing things.
Welcome to the future. ✨
Top comments (9)
This is such a try-hard article trying to sell Neuer.
But bro, what happened with the Svelte component? Afraid much?
You get full Intellisense:
And this is how it looks like being used:
Where are the Svelte examples ... did you realize it isn't that bad at all? Inheritance and early abstraction is bad ... code duplication is good, for a while. Abstract when it makes sense. And then you can make those components easily customizable via props ...
Thank you for sharing your thoughts. This example isn’t about over-abstraction—it’s about Separation of concerns by design.
Of course, a button dropdown is a simplified example. A more compelling real-life use case is something like a
GraphChartComponent
.Imagine the component autonomously pulls its data via an API.
Now, you need a
DonutChart
? Sure, add a prop.Then you want it to use a different base URL endpoint? Another prop.
Now you want an "Export as PNG" button? Another prop—except the original component doesn’t even need this button.
With this props-heavy approach, your once-focused
GraphChartComponent
turns into a bloated, overly generic component, crammed with features it doesn’t always need.Instead, using inheritance, you could create a
DonutChart
orExportableGraphChart
as subclasses, each handling their specific features while reusing the shared logic of the parent. This keeps components modular, clean, and tailored to their purpose without unnecessary complexity.It’s not about controlling everything via props—it’s about creating adaptable components that are easy to extend. Hope that clears things up!
In my distant past, I had a similar perspective, when doing Java stuff, this was basically how you would approach this. But this falls down pretty quickly, believe me (or not, idk). In Java-Land they came up with Dependency-Injecting every "Trait", to get themselves out of the inheritance mess; ... which made it even worse.
Just don't do it. There is nothing bad in rewriting simple things from time to time.
And if you feel the pain of copying code over and over and having to make changes everywhere... make a configurable base component (GraphChartComponent; single point of contact with the wrapped chart library; with just the props you need) and wrap it with specific components (DonutChart, ExportableChart) that do the plumbing (setting default props in the wrapped Component) for you.
No inheritance needed. More flexible. Easier to reason about.
When you come to the point where you have a monolithic BaseComponent exposing all the features of the underlying GraphLibrary (in your example), then you have done the work for them and created a Svelte/React/Vue Component of the ChartLibrary. You might want to gift it to them.
But if you then have the feeling, this is a mess, well, then you should think about using this Library at all; under the hood it looks the same.
Coming from a background in Java and backend development, I've encountered both the strengths and pitfalls of object-oriented programming (OOP) over time.
The key difference, I believe, lies in how changes are introduced and the ripple effects they cause. (And oh gosh, don’t even get me started on the pain of cramming endless configurations into a constructor's mouth—ugh 😂)
When leaning heavily on composition and props, any change often means adding new props or tweaking the base components. This creates a cascading effect: instead of testing a single modification, you now need to regression test the base component and every descendant relying on it.
Contrast this with a clean separation of concerns and direct overriding, where changes are localized and the primary focus stays on the specific functionality being adjusted. The ripple effects are minimized, and you aren’t constantly dealing with regressions.
The props-based approach has its downsides too—it can quickly spiral into chaos. Conditional rendering, hooks, data transformations, and edge cases pile up, leaving you with a bloated JSX monster stretching hundreds of lines. At some point, maintaining or extending such a component becomes so overwhelming that you might find yourself rewriting it from scratch.
And that’s the real kicker: why toss out perfectly good, QA-approved, battle-tested components just to reinvent the wheel for every new use case? Direct overriding offers a more predictable path to adaptation while preserving the integrity of your core components.
Anyway, different domains have different needs, and at the end of the day, it’s all about finding what works best for your context. 😊
Are we pretending slots don't exist in Vue?
And regarding overriding @click, you are correct it's not possible. However, solutions will always look different in each framework. That's not necessarily worse. In this case, you could use a prop called by @click with default behavior. A few extra lines, sure, but not tedious at all and I'd definitely prefer that above writing it the Neuer way with a JSX-looking syntax. Not discrediting Neuer, it's just my personal preference.
And let's not pretend you've not chosen the scenarios where Neuer will shine, surely the other frameworks/libraries will beat Neuer in other regards. It's quite vain to present Neuer as the new Godsend framework-destroyer to save frontend development once and for all. I absolutely appreciate it as an alternative which may have a future among frontend frameworks. Respecting your hard work, and please do make comparisons, but be fair about it and also dare acknowledge the weaknesses of the framework wherever they may be. People deserve to see pros and cons.
Hi! Thank you for sharing your thoughts!
I’m sure every solution has its pros and cons, so I’ll let you decide for yourself what the cons of Neuer might be. Fair enough? 😊
Here’s the Simplest Example
Take a look at this basic implementation of a Neuer-component:
Basic Neuer-component Example
Here’s a Basic To-Do List Example
If you want something a bit more practical, check out this basic to-do list built with Neuer:
Basic To-Do List Example
How to Use These Components
Using Neuer components is super simple! Here’s an example:
How to Use Neuer Components
Neuer: My Baby
Neuer is my baby, so it might not be perfect—but that’s okay! Just in case you want to take a closer look or explore more, here’s the GitHub repo:
Neuer GitHub Repo
I just start with the pros, and you find the cons okay?
No build times.
No assumptions.
Just tools to help you build components yourself, your way.
No link to Neuer?
Is it a framework?
Ezekiel, You Just Asked the Million-Dollar Question!
Is Neuer a framework? HAHAHA, not even close, champ! Neuer is the anti-framework, the liberator, the toolset for devs.
What’s Neuer?
Wanna See What Neuer Can Do?
Check out these links and prepare to have your mind blown:
The Simplest Neuer Example:
Basic Neuer-router Example
A To-Do List (Yes, It’s That Easy):
Basic To-Do List Example
How to Use It:
How to Use Neuer Components
And if you’re the curious type, here’s the repo where the magic lives:
Neuer GitHub Repo
So Ezekiel, is Neuer a framework?
Nope. It’s freedom.