DEV Community

Cover image for When Goliath Fell to David’s Smallest Stone: The Innocent Dropdown Tweak That Shattered React, Vue, and Svelte
Ryo Suwito
Ryo Suwito

Posted on

When Goliath Fell to David’s Smallest Stone: The Innocent Dropdown Tweak That Shattered React, Vue, and Svelte

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:

  1. Version 1: Create a button with a dropdown.
  2. Version 2: Customize the dropdown’s content.
  3. Version 3: Override the click behavior.
  4. 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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
        `;
    }
}
Enter fullscreen mode Exit fullscreen mode

Version 3: Override Click Behavior

Override one method. Done.

export class CustomClickDropdown extends DropdownButton {
    static {
        this.registerElement();
    }
    toggleDropdown() {
        console.log("Custom click logic!");
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
            }
        `;
    }
}
Enter fullscreen mode Exit fullscreen mode

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 (1)

Collapse
 
crenshinibon profile image
Dirk Porsche

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 ...