Svelte vs React: First impressions

Murat Catal
Oct 16, 2019 · 7 min read
Image for post
Image for post
Photo by Coffee Geek on Unsplash

3 years ago, Rich Harris created a framework which is called Svelte. The biggest impact on that new framework was that it’s not working on Virtual DOM like ReactJS, VueJS or AngularJS.

I created exactly same todo list application both in Svelte and React. What i mean with exactly is not only about its functionality or visuality but also i did not used any 3rd party libraries and used their internal APIs to manage a working application.

Our todo application will have listing, adding and removing items. Each items will be stored in a global state. Also there will be component which will subscribe global store and will show current value whenever it changed

Both Svelte and React source codes are on github

Image for post
Image for post
Todo list


$ npx degit sveltejs/template svelte-todo-list
  • Works on DOM, no Virtual DOM
  • Svelte files has .svelte extension
  • Each <style></style> written in svelte files are scoped css.
  • You can use its internal store apis. No need to install an external library
  • Build by Rollup with default configuration. However, you can also use Parsel and Webpack.
  • You can subscribe any variable easily, but it has some hacky ways to detect array mutations. (This one which i didnt like)
  • You can write both javascript, html and styles in svelte files like you are writing a html file. ( has minor difference)
  • You access DOM events with on: prefix such as, <button on:click={} />
  • You do not need to pass callbacks from child to parents. You can use createEventDispatcher.
  • You start a block with {#} and ends with {/} such as {#if}…{/if}

$ npx create-react-app react-todo-list
  • Works with Virtual DOM
  • You can use React’s internal global state management which is called Context API
  • You write purely javascript, you do not have block element syntax special to React like in Svelte ( #if, #each … )
  • DOM events are just javascript events so you can use onClick like how it’s written in purely javascript (standart DOM event for click is onclick! however your OnCLICK oNCLiCk will also be rendered by browser.)
  • File extension is .js

Let’s compare some key points between Svelte and React.

import TodoHeader from "./TodoHeader.svelte";
import TodoList from "./TodoList.svelte";
import { itemStore } from "./store";
main {
font-family: sans-serif;
text-align: center;
<div>Total item: {$itemStore.length}</div>
<TodoHeader />
<TodoList />
import React from 'react';
import './App.css';
import { TodoHeader } from './TodoHeader';
import { TodoList } from './TodoList';
import { TodoListProvider } from './store';
import { Total } from './Total';
function App() {
return (
<TodoListProvider todoList={[]}>
<Total />
<TodoHeader />
<TodoList />
export default App;

App files are entry points in both framework. There is not much difference between two, they both have components to render. The only difference is here that global style binding. In React, a Wrapper Component for React.ContextAPI is a parent of all children whereas in Svelte, you do not need a wrapper for global state.


import { writable } from "svelte/store";const createItemStore = () => {
const { subscribe, update } = writable([]);
return {
addItem: newItem => update(items => {
if (!items.find(item => item === newItem)) {
return items;
removeItem: removedItem => update(items => {
const newItems = items.filter(item => item !== removedItem);
return newItems;
export const itemStore = createItemStore();


import React, { useState } from 'react';export const TodoListContext = React.createContext({});export const TodoListProvider = ({ todoList, children }) => {
const [todos, setTodos] = useState(todoList);
const addItem = (item) => {
if (!todos || !todos.find(listItem => listItem === item)) {
setTodos([...todos, item])
const removeItem = (item) => {
todos.filter(listItem => listItem !== item)
return (
todoList: todos,
export const TodoListConsumer = TodoListContext.Consumer;

These two store does same things. They have both action methods to mutate store data. However, in React using Context API and creating same structure like in Svelte can be some painful. As shown in above example, at first, we created a Context from createContext and in our Provider we had to use hooks to store values locally. Things are more simpler in Svelte, you just create a writeable store and initialize its value and return your value with its actions.


import { itemStore } from "./store";
const handleRemoveItem = item => {
ul {
list-style-type: none;
{#each $itemStore as item}
<button on:click={() => handleRemoveItem(item)}>Remote Item</button>
{#if $itemStore.length === 0}
<div>There is not any item added. Please add one</div>


import React, { useContext } from 'react';
import { TodoListContext } from './store';
export const TodoList = () => {
const todoListContext = useContext(TodoListContext);
const handleRemove = (item) => {
const { todoList } = todoListContext;return (
{todoList && => {
return (
<button onClick={handleRemove.bind(null, todoList)}>Remote Item</button>
{(todoList.length === 0) && (<div>There is not any item added. Please add one</div>)}

The thing that forced me writing my first Svelte application was using conditions and loops in component. Using syntax another then pure javascript for loops or conditions are the things i do not like. But, accessing store item with only import and not needing to any external hook or layer for accessing global store is the key difference between Svelte and React.


import { onMount } from "svelte";
import { itemStore } from "./store";
let value;
onMount(() => {
value = "";
const handleAddItem = () => {
value = "";
.disabled {
color: graytext;
<input type="text" bind:value placeholder="Item name" />
<button on:click={handleAddItem} disabled={!value} class:disabled={!value}>
Add Item


import React, { useContext, useState } from 'react';
import { TodoListContext } from './store';
export const TodoHeader = () => {
const todoListStore = useContext(TodoListContext);
const [itemName, setItemName] = useState('')
const handleAddItem = (e) => {
return (
<input placeholder="Item name" type="text" value={itemName} onChange={(event) => setItemName(} />
<button onClick={handleAddItem} disabled={!itemName} className={!itemName && 'disabled'}>Add Item</button>

In Svelte, you do not need to store your input’s value in a state externally. Svelte makes it easier with binding keyword to any existing property, with a plus additional feature that you can track that prop changes with reactive declaration without extra effort for values (not for arrays).

Also, let’s share some results about building process, difficulty and conveniences which i faced while developing.

I followed exactly same pattern while developing both. I did not use any external libraries and used only internal API’s both frameworks support. There are components connected to global state. There are components subscribed to global state variables.

  • Building is really fast. But this may be also because of using Rollup as a bundler, i think it would be good to test bundling with Webpack also.
  • Again bundle size is really small against React. However this may be also because of Rollup’s tree-shaking performance.
  • It’s store usage is really flexible. You can adapt your components within store and start subscribing or mutating store values easily. ❤️
  • I liked all styles written in a component are scoped css.
  • Binding a conditional style has easy syntax which you do not need to create a logic for class binding. (class:disabled=variable)
  • I really do not like writing templates in a file, such as #each , #if. I do not like to prefer using new approaches for which i can do it with purely in JavaScript.
  • When you use reactive declarations to subscribe a variable change, Svelte can not detect mutations on arrays. Svelte offers some hacky ways for that situation.
  • Some developers may like writing templates in a component however this one is still what i could not like. Also, this approach leads using templates for loops, conditions etc which i referred in item 1.
  • You should give a unique id for each item in a list, otherwise whenever you want to get an action on the item in list, a wrong item could be effected.
  • Usage style in DOM events such as on:click is one of the things i do not like. I prefer using onClick as a normal DOM event. (standart DOM event for click is onclick! however your OnCLICK oNCLiCk will also be rendered by browser.)

SvelteJS uses Rollup and ReactJS Webpack in defaults and i didn’t touched their configurations, they have both default configuration. Svelte built time was 1.40s where React builds 5.49s. Here Svelte wins! ❤️

Image for post
Image for post
Build Times

Both application is server by serve npm package. Svelte exports its bundles into public folder whereas react app put them into build folder.

serve -s build  // this is for react app
serve -s public // this is for svelte app

When i checked network tab, Svelte’s bundle is just 2.9 KB after gzip whereas React’s bundle is just 42.1 KB after gzip. here again Svelte w️️ins with its bundle sizes on production ❤️

Image for post
Image for post
Svelte vs React in production build instead of size

If you like my articles, you can support me by clapping and following me.
I’m also on
linkedin, all invitations are welcome.

JavaScript In Plain English

New JavaScript + Web Development articles every day.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store