Choosing a frontend framework

A question I've gotten a few times after my talk or sharing Svelte by Example is which frontend framework I'd choose these days.

Here's the good news: these days you can't really go wrong with any of the major frameworks—at least from a technical perspective. React, Vue, Svelte, Angular… all have incredible teams, contributors & ecosystems backing them. Your frontend framework will not be the limiting factor of your architecture.

Choose a framework based on the non-technical needs of your team. If scaling up your team is important, React might make more sense because of its popularity on the job market. On the other hand, if your team hates the mental model of React, don't feel pressured to use it regardless of its popularity. Choose your framework based on how it aligns with your team's programming values, not performance needs. (Unless you're building a Bloomberg terminal.)

My preference these days: I'm split between React & Svelte. (That is, when I'm working on a project I deem worthy of a JavaScript-heavy interface, for others I still prefer vanilla JS or Alpine.) I like them both because they each have a distinct direction. React is as JavaScript as a JavaScript framework can be, while Svelte stays as close to HTML & the DOM as possible. What they have in common is they've chosen a slice of the stack, and double down on enhancing it. I prefer tools with distinct directions.

Dan Abramov: The two Reacts

Frontend frameworks often use the mental modal that a component (or entire UI) is the result of running state through a pure function. Dan Abromov shares his thoughts on the current state of React with server components.

UI = f(data)(state)

Here's how I interpret it: in the mental model we're used to, a component is a pure function that returns UI based on its props. In this case, a Greeter is rendered on the client.

function Greeter(props) {
return <p>Hello, {}!</p>;

Say we have a server component that know who needs to be greeted before the code hits the client. In that case, the name will come from data available on the server.

function Greeter(data) {
return function () {
return <p>Hello, {}!</p>;

The outer function is executed on the server, the inner on the client.

The true power lies in mixing and matching the paradigms. Say you want to read a translation string on the server, and greet a name on the client.

function Greeter(data) {
return function (props) {
return <p>{data.translations.hello}, {}!</p>;

Elise Hein: 'Fighting inter-component HTML bloat'

As I'm refactoring an existing design system, this article by Elise Hein came quit timely.

We consider HTML to be cheap, but wrapping divs in divs in divs comes with a cost that slowly creeps up.

Why avoid extra wrapper elements?

  1. Bloated html hurts performance
  2. Redundant elements can create problems with accessibility
  3. Redundant elements can break styling
  4. Deeply nested dom trees are annoying to work with

Rauno's web interface guidelines

Rauno Freiberg (designer at Vercel) shares his web guidelines for web interfaces. A few that stood out for me:

  • Inputs should be wrapped with a <form> to submit by pressing Enter
  • Interactive elements should disable user-select for inner content
  • Actions that are frequent and low in novelty should avoid extraneous animations

Read them all on Rauno's (beautiful) website, and check out the Craft section while you're there.

Vite with Laravel

I've had an eye on Vite for a while. With a stable release out the door (2.0, as 1.0 never left the release candidate stage) it seemed like a good time to give it a shot.

Vite is a frontend build tool like webpack. Instead of bundling development assets, Vite serves native ES modules transpiled with esbuild from the dev server. This means there's a lot less bundling to do, and results in a very fast developer experience. For production builds, Vite uses Rollup to bundle the assets.

Read more

The complexity that lives in the GUI

RoyalSloth reviews the three most common patterns to model interconnected state in a user interface.

  • Connect the boxes: create the user avatar component and pass its instance to the inventory table component
  • Lift the state up: move the internal state of the user avatar component and the state of the inventory table into a separate box/class
  • Introduce a message bus: connect the inventory table and the user avatar component to the shared pipe that is used for distributing events in the application

Connect the boxes and lift the state up seem to be the most common choices for React apps; respectively prop drilling and context or single state trees (like Redux).

There's no silver bullet to UI complexity, all methods have their caveats.

Read the full article on