NEW

Prismic offers an ideal solution to feature your e-commerce products in your promotional landing pages or inspirational content. View more

Svelte vs. React in 2022: Choosing the Best Match for You

Written by Ben Holmes in
engineering
on February 03, 2022

Let’s kick things off with an anecdote. I was speaking with an 11ty developer the other day, as they planned their move from pure front-of-the-frontend tech (plain HTML and CSS) into the world of JavaScript-infused component frameworks. They were open to any of the popular options from React to Vue to Svelte.

Because of its popularity, they tried React first.

And hated it. (Their words, not mine. 🙃)

It just didn't meld with their approach or mindset as web developers, informed by building well-crafted websites markup-first.

Undeterred, they sampled some different tools in the ecosystem: Vue and Svelte.js. Their reaction to each of these was completely different! Building interactive websites was easier than ever; it gelled with their philosophies as devs; and the production output was roughly the same as something React could accomplish. Svelte was the best match for them.

Now let me share another example: I led a web development boot camp back in college targeted at computer science students. The first few weeks learning plain HTML, CSS, and JavaScript were ... quite rough to say the least. Understanding cascading styles and accessible HTML just didn't “click” for those cranking out Java homework every day. The tech felt simple, but not easy.

But once we introduced React, people's mindsets started to change. One student picked up the class-based syntax championed in React's docs at the time, saying, "This feels similar to the classes I wrote in Java!" Crafting UIs JavaScript-first worked for those in the CS space. React was the best match for them.

I just presented two anecdotes on a whole spectrum of development backgrounds. So if your team is comparing React and Svelte, which is the better match?

Let's compare:

  • 🗣 The syntaxes used by each of these component frameworks
  • 🔨 Their guiding principles
  • 🏡 The origins that informed their API designs

... to help you choose the right tool for the job 🔧

Disclaimer: this is not a popularity contest

Higher downloads do not mean higher quality.

Other React vs. Svelte pieces may start with the download numbers. So ya know what? Here are the npm stats at the time of this writing. You can click the links to fact check me. 🙃

  • 📦 Svelte: over 100,000 weekly downloads
  • 📦 React: over 6 million weekly downloads

So yeah ... React’s still freaking huge.

I totally understand if you want the incumbent, no matter which your team prefers. But here’s my opinion: higher downloads do not mean higher quality. Every library makes design trade-offs to satisfy developer needs. So not every developer, nor every team, is going to be as productive with the same tool.

I also want to address any mistrust in the underdog. First, Svelte’s community is now more than large enough to tackle sites and complex web apps at the enterprise level. Just see the plethora of 3rd party libraries available for design systems, CMS integrations, embeds, and more. Scott Tolinski’s case study on migrating his entire course platform to Svelte is worth a watch, too.

What’s more, Svelte isn’t a hobby project these days. It’s now maintained full-time by its creator and backed by Vercel.

All this to say — we’re not going to compare communities and ecosystems today. Each tool is more than competent in this regard! We’re here to explore how these tools work and what problems they’re designed to solve.

Let’s build a collapsing nav menu with each tool

We’ll start by comparing React and Svelte’s approach to the same UI problem: show / hide interactions. Take this collapsing nav menu for instance:

A gif previewing a menu that toggles to show and hide itself when users click a hamburger-style icon.

I wrote a full guide on considering styles, keyboard navigation, and screen reader accessibility for this. But we’ll focus on that juicy hamburger toggle alone for simplicity 🍔

Let’s try React

TL;DR

Just in case you don’t have time for this awesome tutorial, here’s a quick summary of what it reveals:

  • React is built for programmers. JavaScript first, backed by functional programming principles.
  • React is platform-agnostic. As long as (props) ⇒ UI, your components could work both inside and outside the browser.
  • React is predictable. Every component is considered “pure,” and the resulting UI is based on the properties you pass in.
  • React is testable. All impurities are wrapped in a useEffect, and all state changes are wrapped in a useState. This ensures 1) easy mocking of outer dependencies, and 2) the line between pure and impure is clear from the code.

Building our first React component

💡 This section assumes you have a beginner’s knowledge. If you already know React, jump to React encourages functional programming 👇 Otherwise, feel free to follow along from this Stackblitz sandbox.

There are two UI elements to consider in our example: the menu button and the list of links we’re revealing.

We’ll start with a new React component to encapsulate this:

 
// src/DropdownNav.jsx
import React from 'react'

export default function DropdownNav() {
  return (
    <nav>
      <button>Menu</button>
      <ul>
        <li>Home</li>
        <li>About</li>
        <li>Projects</li>
        <li>Contact</li>
      </ul>
    </nav>
  )
}

And to use this inside of other components, we can “call” DropdownNav like it’s an HTML element:

 
// src/App.jsx
import DropdownNav from './DropdownNav'
import React from 'react'

export default function App() {
  return (
    <main>
      <DropdownNav />
      <p>Cool site</p>
    </main>
  )
}

We immediately notice something interesting: we start with a JavaScript function, then return our UI from that JavaScript. This falls in line with React's programmer-first mindset, which we’ll explore throughout the post.

We’re also able to write HTML in our return statement as if it’s plain HTML. This is because we’re not working inside regular JavaScript here! We’re using a .jsx file, which allows us to write something HTML-like (learn more about JSX here) alongside otherwise “plain” JavaScript. As you can imagine, you’ll need some extra tools to compile JSX into something the browser can understand. I won’t dive too deeply into build configs here, but Vite is a great choice if you crave simplicity. 😁

Wiring up our show / hide interaction

Let’s make our button actually do something. We’ll need a variable to keep track of whether or not the menu is showing, which we can accomplish with a “React hook" called useState:

 
import React, { useState } from 'react'

export default function DropdownNav() {
  // create a getter + setter to manage our nav
  // isExpanded - our state variable starting at "false"
  // setIsExpanded - setter to update this value
  const [isExpanded, setIsExpanded] = useState(false)
  function clickHandler() {
    // toggle our "isExpanded" state to its opposite
    setIsExpanded(!isExpanded)
  }
  return (
    <nav>
      {/* apply our handler to the button's click event */}
      <button onClick={clickHandler}>Menu</button>
      {/* when expanded: return the <ul> from our component */}
      {/* when collapsed: don't return the <ul> */}
      {isExpanded ? <ul>...</ul> : null}
    </nav>
  )
}

You can think of isExpanded like a regular JavaScript variable, but with one key difference: changing the value tells React to update our UI. Whenever setIsExpanded is called, React will re-evaluate our DropdownNav function to figure out what to show on the page. Because of that ternary inside our UI, React will:

  • Include the <ul> on our page when isExpanded is true
  • Omit the <ul> from our page when isExpanded is false

React encourages functional programming

React’s components and hooks are inspired by the computer science concept of functional programming. Note I say “inspired by” here; React isn’t a strict functional programming paradigm like, say, Haskell. But it encourages some important functional programming principles!

First, components should be “pure” functions. This means that, for a given input, you’ll always receive the same output. Consider a simple component like this:

 
function MakeFun({ boringText }) {
  return <p>✨ {boringText}! ✨</p>
}

I don’t need to worry if my paragraph exists in the document, outside dependencies exist, and so on. <MakeFun boringText="react" /> will always give me <p>✨ react! ✨</p>.

💡 This purity also makes React platform-agnostic. For instance, React Native applies these same components to building native apps for iOS and Android (yes, not just a browser-wrapped-in-an-app — really native!). As long as you can call a function and get some UI back, who cares where it’s running?

Second, anything that’s impure should be extracted away. Remember that React calls your component function with a sole purpose: figure out what UI to show for a given set of props. Anything outside that purpose (fetching content from an API, querying the browser document, triggering state changes programmatically, etc.) is considered an impurity, or a "side effect."

React provides a helper for this called useEffect. Say we’re fetching a funny joke from the Dad Jokes API:

 
import React from 'react'

function MakeMeLaugh({ name }) {
  const [joke, setJoke] = React.useState('Let me think of something ...')
  // fetching shouldn't block our UI! Let's make it a side effect.
  React.useEffect(() => {
    // query the API, and setJoke when we get a response
    fetch('https://icanhazdadjoke.com/', {
      headers: { Accept: 'application/json' },
    })
      .then((res) => res.json())
      .then((jokeInfo) => setJoke(jokeInfo.joke))
    // [name] is our dependency array
    // aka fetch a new joke any time the person's "name" changes
    // everyone deserves a unique joke 🙃
  }, [name])

  // render our joke, which is either:
  // 1. some placeholder text on initial render
  // 2. a joke from our API
  return (
    <p>
      A joke just for {name}: {joke}
    </p>
  )
}

Play with this example on Stackblitz ⚡️

When we put this component on our page as <MakeMeLaugh name="Ben" />, React will do the following:

  1. Render “A joke just for Ben: Let me think of something...”
  2. Queue up any side effects it found while rendering. In this case, our fetch call.
  3. Execute our fetch call. Then 👉 setJoke is called. This tells React, “Hey, you should re-render this component!”
  4. Render a terrible joke like “A joke just for Ben: I saw an ad in a shop window, ‘Television for sale, $1, volume stuck on full.’ I thought, ‘I can't turn that down!’” ... Don’t worry, I eye-rolled with you 🙄

☝️ Notice that step one isn’t “call an API.” It’s “render our UI, and schedule API calls for later.” This has a few benefits:

  • The first render is always predictable. This is vital when building complex web applications since users will always see the same initial content before side effects are run.
  • This predictability makes components testable. We could make a unit test to verify what our component shows at first and mock our side effect with something like React Testing Library. No need to mock the fetch call itself; since useEffect incapsulates impurities, this is the only piece to worry about.

💡 I mentioned earlier how React is far from a “true” functional programming language like Haskell. Heck, the existence of useState or useEffect makes every React component impure: they’re outside dependencies! This is why some devs want React to go from a library to a true programming language. If you’re interested, check out Dan Abramov’s thoughts on effects or the rescript programming language.

Now let’s try Svelte

We’ve explored the “how” and “why” of React. Now let’s get Svelte-y 🕺

TL;DR

Here’s another quick overview of what the tutorial reveals:

  • Svelte is simple. It’s built to let you ship faster, so it’s happy to abstract state management away.
  • Svelte is batteries included. Styles and animations have out-of-the-box solutions.
  • Svelte is UI first. It’s <nav />, not function() { return <nav /> }.
  • Svelte is built for the web. To include those batteries, Svelte chooses to embrace existing web APIs. This makes Svelte less transportable to native applications on mobile or desktop. But it’s part of the secret sauce to simplicity. 🌶

Building our first Svelte component

💡 Svelte has a great REPL playground to follow along with. You can start from their Hello World for this section. But for future reference, it features a guided tutorial / playground to explore styles, transitions, state management, and more. Worth a look if you’re a new user!

Let’s dive into that same dropdown menu from before. We’ll create a DropdownNav file, this time using .svelte instead of .jsx.

 
<!--DropdownNav.svelte-->
<nav>
  <button>Menu</button>
  <ul>
    <li>Home</li>
    <li>About</li>
    <li>Projects</li>
    <li>Contact</li>
  </ul>
</nav>

Woah! We just put our HTML right at the top, no functions necessary. This speaks to Svelte’s leaning towards simplicity. You’ll notice this in the next few snippets too. 😉

But make no mistake! React and Svelte share the same concept of “building with components.” You’ll import and place this dropdown inside other components similar to React:

 
<!--App.svelte-->
<script>
  import DropdownNav from './DropdownNav.svelte'
</script>

<DropdownNav />
<p>Svexy website!</p>

☝️ Since Svelte is HTML-like, you’ll include any import statements inside a script tag. The same goes for concepts like state management as well. Let’s wire up our show / hide toggle:

 
<script>
  // state variables are just ... variables
  let isExpanded = false

  function clickHandler() {
    // to update a state variable ... update the variable 😉
    isExpanded = !isExpanded
  }
</script>

<nav>
  <!--wire up click handlers similar to React-->
  <button on:click={clickHandler}> Menu </button>
  <!--use some Svelte-specific syntax for conditionals-->
  {#if isExpanded}
    <ul>...</ul>
  {/if}
</nav>

Huh, well that was uneventful. No need to import a state handler, create a setter function, write a head-scratching ? : ternary for our list, etc. Just manipulate JavaScript variables like any other variable, and let Svelte’s compiler handle the rest.

Svelte helps you ship faster

This is the mantra Rich Harris (creator of Svelte) has been using as of late. Where React favors functional programming principles and a JavaScript-first mindset, Svelte ditches the dogma for a whole-new templating syntax. This lets Svelte bundle all sorts of built-in functionality. For instance ...

Built-in style scoping

Here’s how we could style that dropdown from earlier via CSS:

 
<style>
.container {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.button::before {
  content: '🍔';
}
</style>

<nav class="container">
  <button class="button"> Menu </button>
  <ul>...</ul>
</nav>

Not only will these styles get applied in our dropdown, but they’ll also be scoped specifically to our component. This means selectors like .container can’t bleed outside our component into other elements with a class="container" 🏆 If you have nightmares of managing the “cascade” of CSS from older projects ... rejoice!

Built-in animation helpers

Svelte also bundles a transitions library to make UIs more engaging. We can make our dropdown truly expand and collapse with a one-line change. 👀

A demo of how Svelte's built-in animation helpers work: "transition:slide" is added to the unordered list within a nav HTML element, making the animation demonstration have a smoother effect.

Play with this example on REPL

This is the first popular UI framework I’ve seen that makes animation a first-class citizen. What’s more, it’s simple to write your own transition directives to use elsewhere in your app. Just take in the duration + other custom parameters, and emit some CSS to apply as a transition. Learn more from their walkthrough tutorial 👀

💡 You might be wondering “well, does React help with styles and animations?” In short: no! Not without some helper libraries anyways. But thanks to React’s enormous userbase, these problems have been solved many times over by popular 3rd party packages.

Let’s stop and compare: React vs. Svelte

You’ll notice I spent most of the React section talking about “how does it work?” while I spent most of the Svelte section on “what can it do?” That’s for a reason. Their guiding principles are completely different. 😮

  • React is a library with strong opinions on managing UI with JavaScript and few opinions on the UI itself. This is by design, of course; React’s functional programming approach makes it a great choice for programmers who want to ship to browsers, native apps, and more. But if you want to handle styles or animations, you better find more npm packages.
  • Svelte is a framework with strong opinions on the UI itself, while hiding the JavaScript that gets you there. Necessities for building websites are often baked-in, making it perfect for web developers who want to ship websites fast. Check your programming paradigms at the door and write some HTML. 😉

Is there a lot of overlap between these target audiences? Absolutely. Since they’re each component-based approaches to web development, I’m personally happy to switch between React and Svelte on a whim. But readers on the fringes of “HTML-first web developer” and “backend engineer getting into UIs” may gravitate towards one or the other (Svelte and React respectively).

You may have some questions about these lines I’ve drawn though. Maybe their origin stories will help 👇

#React was built to solve state management at scale. #Svelte was built to bring interactivity cheaply (good UX) and simply (good DX). #SveltevsReact

Different origins

It’s worth mentioning the origins of each of these tools since they definitely informed their overall design decisions.

  • First, React was built to solve state management at scale. It was created (and continues) to solve Facebook’s needs as an ultra-dynamic web app. Most of their challenges boil down to fetching data as smartly as possible, and managing that data as the user navigates the app.
  • Meanwhile, Svelte was built to bring interactivity cheaply (good UX) and simply (good DX). Rich Harris maintained Svelte as a developer for the New York Times. News articles were generally static content coming from a CMS, but they often experimented with interactive visuals as well. So, Rich found a clean way to embed components of HTML, and bind JS-driven data visualizations with enough helpers to ship at the speed of news.

☝️ Am I stating React is always best suited for web apps, and Svelte is always better for mostly static sites? No! (Though swyx might 👀) I personally think they can each solve the same set of problems. Just understand that their developer ergonomics will be informed by the use cases I listed. So if your team is building a site closer to the New York Times or closer to Facebook, you might bias towards one tool or the other.

What came first: the state or the UI?

This is the chicken-and-the-egg problem of modern front-ends. And each tool has a different answer:

  • React lets you write JavaScript that returns the resulting UI: (state) ⇒ UI
  • Svelte lets you write your UI first, then bind interactivity as needed: UI.bind:state

This makes Svelte feel much simpler when there’s no JavaScript involved, as function DropdownNav() { return <nav /> } simply becomes... <nav />. Web developers with a templating background (Nunjucks, Vue, Angular, plain HTML, etc.) will likely feel more at home.

But beyond the lessened boilerplate, you may still prefer Svelte for more complex state management as well. 👀

Controlled inputs are a classic example of why. Say we have a text input, and we want to set our site’s heading to whatever’s inside that input. This means our text updates as the user is typing. Here’s one React solution:

 
import React from 'react'

function ControlFreak() {
  // craft your state first
  const [input, setInput] = React.useState('')
  return (
    <>
      <h1>{input}</h1>
      {/* attach state to the return value */}
      {/* plus an event listener to trigger rerenders */}
      <input value={input} onInput={(e) => setInput(e.target.value)} />
    </>
  )
}

And the same in Svelte:

 
<!--Write our HTML and "bind" some JavaScript to it-->
<h1>{input}</h1>
<input bind:value={input}>

<script>
    // create a variable to receive that binding
    let input = '';
</script>

Some may prefer React’s explicitness; a majority of the code is JavaScript-driven, and little is left to the imagination (notice Svelte “magically” set the onInput property for us here). Others may love the simplicity of Svelte and accept the magic. React is thorough, while Svelte lets you ship faster ™️ .

Note: not actually trademarked. They should jump on that though 😉

Which do we choose?

We’ve walked through quite a few contrasts between React and Svelte. This is a non-exhaustive list of course, but let’s enumerate why teams might prefer one tool or the other.

When React is a good fit

  • Your team has a stronger programming background. You may have full-stack engineers with hands in backend technologies, functional programming fanatics, JavaScript gurus, etc.
  • Your projects are extremely dynamic and data-driven. React is built to solve state management at scale, so the level of tooling (both first and third party) is second to none.
  • You plan to reuse your work across platforms. React is framework agnostic by nature, so React Native for mobile and desktop apps + ReactJS for the web is a nice pairing.

When Svelte is a good fit

  • Your team has a stronger front-end background. You may have front-end devs with templating language experience, confidence with CSS and page animations, etc.
  • Your projects are UI-centric and built for the web. Svelte is a batteries-included framework with CSS, animation, and even 3D solutions baked-in. React requires 3rd party solutions for each of these.
  • Your team needs to ship by yesterday. Svelte trades thoroughness for simplicity, so you’ll find yourself writing less code day-to-day (that’s still quite human-readable).

Comparing core feature sets

A visual recap of the TL;DR sections written out above. In summary, React is built for programmers, is platform-agnostic, is predictable, and is testable. Svelte is simple, has styles and animations with out-of-the-box solutions, is UI first, and is built for the web.

If you’re undecided ...

Have your team sample both! You may find switching between React and Svelte especially useful on a project-by-project basis.

Also, share this article around and have your developers pick apart the code demos. Web development isn’t about punching code into a computer; it’s a language for people to communicate their ideas. So I definitely recommend sparking a discussion to find the right language for the job 😁

☝️ If you enjoyed this comparison, you might also like: How to Make a Website with SvelteKit

Profile picture

Ben Holmes

Frontend dev exploring how the web works. Creator of @slinkitydotdev, full-time dev at @onepeloton.

More posts