The Wider Landscape: Vue, Svelte & Signals

Expert · 18 min read · ▶ live playground · ✦ checkpoint

React is a major road, not the whole map. Vue, Svelte, Solid, and Angular all attack the same problem you already know: some fact changes, and the screen must match without a trail of hand-patched DOM updates.

Stop asking "which one is best?" in the abstract. A framework is a set of tradeoffs, like choosing a vehicle for a route: bike, train, and truck can all be excellent when the job fits.

Four framework shapes

Vue is a component framework that often keeps markup, script, and styles together in a single-file component, one file that describes one component's template, behavior, and styling. A template is an HTML-like view section with slots for data. Vue's default feel is approachable: templates look close to HTML, while state and derived values live in script.

<script setup>
import { computed, ref } from "vue";
 
const tasks = ref([
  { id: 1, title: "Draft release note", done: false },
  { id: 2, title: "Pay invoice", done: true },
]);
 
const openCount = computed(() =>
  tasks.value.filter((task) => !task.done).length,
);
</script>
 
<template>
  <p>{{ openCount }} open</p>
</template>

Svelte is a compiler-centered framework, which means a build tool rewrites your component source into efficient browser JavaScript before it runs. Svelte 5 uses runes, special syntax markers such as $state that tell Svelte which values are reactive.

<script>
  let openCount = $state(2);
</script>
 
<button onclick={() => openCount += 1}>
  {openCount} open
</button>

Solid is a component framework built around signals from the start. Its code can look JSX-shaped, but its update model is different from React's render snapshots: small reactive values notify the exact computations that read them.

import { createMemo, createSignal } from "solid-js";
 
function TaskSummary() {
  const [tasks] = createSignal([
    { id: 1, title: "Draft release note", done: false },
    { id: 2, title: "Pay invoice", done: true },
  ]);
 
  const openCount = createMemo(() =>
    tasks().filter((task) => !task.done).length,
  );
 
  return <p>{openCount()} open</p>;
}

Angular is a full application framework, not just a view layer. It brings strong conventions for components, templates, forms, HTTP, routing, testing, and project structure. Angular often uses a decorator, metadata attached to a class, to connect code with a template.

@Component({
  selector: "task-summary",
  template: `<p>{{ openCount }} open</p>`,
})
export class TaskSummaryComponent {
  tasks = [
    { id: 1, title: "Draft release note", done: false },
    { id: 2, title: "Pay invoice", done: true },
  ];
 
  get openCount() {
    return this.tasks.filter((task) => !task.done).length;
  }
}

These examples are not four separate religions. They are four ways to split responsibility: where the template lives, where state lives, what the build step understands, and how updates find the right screen pieces.

Virtual DOM and signals

A virtual DOM is a JavaScript description tree of the UI that a library can compare before touching the real DOM. Think of it as a draft seating chart: the host compares the new chart with the old one, then moves only the guests who changed tables.

A signal is a small reactive value that remembers which computations read it. Think of a signal as a labeled wire: when the value changes, only the devices connected to that wire need to wake up.

That is why the trend line matters. Signals are everywhere: Svelte 5 has runes, Solid is signal-first, Vue Vapor is in beta, and TC39 has a Signals proposal at Stage 1. Do not read that as "all frameworks are becoming the same." Read it as "the whole ecosystem is paying attention to precise updates."

Try it — a tiny signal-shaped update

This is not Solid, Vue, or Svelte. It is a small plain-JavaScript toy that shows the core signal idea: a value is read during a computation, then that computation reruns when the value changes.

javascript — live consolereal engine
⌘/Ctrl + Enter to run

The important line is not a framework API. It is tasks() inside openCount(). Reading the signal while autorun is active lets the signal remember the subscriber. Later, setTasks(...) wakes that subscriber. Real frameworks add cleanup, batching, scheduling, errors, dev tools, and DOM integration.

How to choose

Choose a framework by pressure, not by mood.

If a team already has a mature React app, the best choice is usually React because the codebase, tests, hiring, and deployment path already point there. If a small team values templates close to HTML, Vue may fit. If you like compiler-shaped components with little runtime ceremony, Svelte may fit. If you want signal-first precision and are comfortable with a smaller mental model that feels different from React, Solid may fit. If an organization wants one broad, official app structure with routing, forms, HTTP, and testing patterns built in, Angular may fit.

Also ask the boring questions. Are the docs good enough for your team? Can you test it? Can you hire or train people? Does it handle accessibility patterns well? Does it work with your deployment target? Does the ecosystem already solve the hard parts your app needs?

The six-month mistake is choosing by headline. New framework excitement is like fresh stationery: planning feels productive for a day, then the real work returns. Build one small spike when the choice matters, compare the same screen in each candidate, then commit. Re-choose only when the current tool has become a real constraint, not when a feed gets loud.

You now have the front-end framework map: React's render snapshots, Vue's approachable components, Svelte's compiler, Solid's signals, and Angular's full-app structure. Next, the question moves from "which UI model?" to "where does rendering happen?" with CSR, SSR, SSG, streaming, hydration, islands, and server components.

Checkpoint

Answer all three to mark this lesson complete

+50 XP on completion