32 KiB
Component Party 🎉
Web component JS frameworks quick overview by their syntax and features
Website: https://component-party.pages.dev
Why ?
Many JS developers don't have a good overview of every existing JS framework with their own syntax and features. How do we solve this ? Developers love having framework overview by examples. It's a quick introduction before going deeper.
Roadmap
- Add Angular support
- Add SolidJS support
- Add Preact support
- Add Alpine support
- Website (built with Astro)
- Add React support
- Add Svelte support
- Add Vue 3 support
Contributing
This site is built with Astro. Site content is written in Markdown format located in content. For simple edits, you can directly edit the file on GitHub and generate a Pull Request.
For local development, pnpm is preferred as package manager:
pnpm i
pnpm run dev
This project requires Node.js to be v14.0.0 or higher, because we use new JavaScript features in our code, such as optional chaining.
Reactivity
Declare state
Svelte
<script>
let name = 'John';
console.log(name); // John
</script>
React
import { useState } from 'react';
export default function Name() {
const [name] = useState('John');
console.log(name); // John
}
Vue 3
<script setup>
import { ref } from 'vue';
const name = ref('John');
console.log(name.value); // John
</script>
Angular
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-name',
})
export class NameComponent {
@Input() name: string = 'John';
constructor() {
console.log(this.name);
}
}
Update state
Svelte
<script>
let name = 'John';
name = 'Jane';
console.log(name); // Jane
</script>
React
import { useState } from 'react';
export default function Name() {
const [name, setName] = useState('John');
setName('Jane');
console.log(name); // Jane
}
Vue 3
<script setup>
import { ref } from 'vue';
const name = ref('John');
name.value = 'Jane';
console.log(name.value); // Jane
</script>
Angular
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-name',
})
export class NameComponent {
@Input() name: string = 'John';
constructor() {
this.name = 'Jane';
console.log(this.name);
}
}
Computed state
Svelte
<script>
let count = 10;
$: doubleCount = count * 2;
console.log(doubleCount); // 20
</script>
React
import { useState, useMemo } from 'react';
export default function DoubleCount() {
const [count] = useState(10);
const doubleCount = useMemo(() => count * 2, [count]);
console.log(doubleCount); // 20
return <div />;
}
Vue 3
<script setup>
import { ref, computed } from 'vue';
const count = ref(10);
const doubleCount = computed(() => count.value * 2);
console.log(doubleCount.value); // 20
</script>
<template>
<div />
</template>
Angular
import { Component, OnInit, Input, Pipe, PipeTransform, ChangeDetectionStrategy } from '@angular/core';
@Pipe({
name: 'double',
})
export class DoubleCountPipe implements PipeTransform {
transform(value: number): number {
return value * 2;
}
}
@Component({
selector: 'app-doublecount',
template: ' <div></div>',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DoublecountComponent implements OnInit {
@Input() count: number = 10;
constructor() {}
}
Templating
Minimal template
Svelte
<h1>Hello world</h1>
React
export default function HelloWorld() {
return <h1>Hello world</h1>;
}
Vue 3
<template>
<h1>Hello world</h1>
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Styling
Svelte
<h1 class="title">Hello world</h1>
<button style="font-size: 10rem;">I am a button</button>
<style>
.title {
color: red;
}
</style>
React
export default function HelloWorld() {
// how do you declare title class ??
return (
<>
<h1 className="title">Hello world</h1>
<button style={{ 'font-size': '10rem' }}>I am a button</button>
</>
);
}
Vue 3
<template>
<h1 class="title">
Hello world
</h1>
<button style="font-size: 10rem">
I am a button
</button>
</template>
<style scoped>
.title {
color: red;
}
</style>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Loop
Svelte
<script>
const colors = ['red', 'green', 'blue'];
</script>
<ul>
{#each colors as color}
<li>{color}</li>
{/each}
</ul>
React
export default function Colors() {
const colors = ['red', 'green', 'blue'];
return (
<ul>
{colors.map((color) => (
<li key={color}>{color}</li>
))}
</ul>
);
}
Vue 3
<script setup>
const colors = ['red', 'green', 'blue'];
</script>
<template>
<ul>
<li
v-for="color in colors"
:key="color"
>
{{ color }}
</li>
</ul>
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Event click
Svelte
<script>
let count = 0;
function incrementCount() {
count++;
}
</script>
<p>Counter: {count}</p>
<button on:click={incrementCount}>+1</button>
React
import { useState } from 'react';
export default function Name() {
const [count, setCount] = useState(0);
function incrementCount() {
setCount(count + 1);
}
return (
<>
<p>Counter: {count}</p>
<button onClick={incrementCount}>+1</button>
</>
);
}
Vue 3
<script setup>
import { ref } from 'vue';
const count = ref(0);
function incrementCount() {
count.value++;
}
</script>
<template>
<p>Counter: {{ count }}</p>
<button @click="incrementCount">
+1
</button>
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Dom ref
Svelte
<script>
import { onMount } from 'svelte';
let inputElement;
onMount(() => {
inputElement.focus();
});
</script>
<input bind:this={inputElement} />
React
import { useEffect, useRef } from 'react';
export default function InputFocused() {
const inputElement = useRef(null);
useEffect(() => inputElement.current.focus());
return <input type="text" ref={inputElement} />;
}
Vue 3
<script setup>
import { ref, onMounted } from 'vue';
const inputElement = ref();
onMounted(() => {
inputElement.value.focus();
});
</script>
<template>
<input ref="inputElement">
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Conditional
Svelte
<script>
const TRAFFIC_LIGHTS = ['red', 'orange', 'green'];
let lightIndex = 0;
$: light = TRAFFIC_LIGHTS[lightIndex];
function nextLight() {
if (lightIndex + 1 > TRAFFIC_LIGHTS.length - 1) {
lightIndex = 0;
} else {
lightIndex++;
}
}
</script>
<button on:click={nextLight}>Next light</button>
<p>Light is: {light}</p>
<p>
You must
{#if light === 'red'}
STOP
{:else if light === 'orange'}
SLOW DOWN
{:else if light === 'green'}
GO
{/if}
</p>
React
import { useState, useMemo } from 'react';
const TRAFFIC_LIGHTS = ['red', 'orange', 'green'];
export default function TrafficLight() {
const [lightIndex, setLightIndex] = useState(0);
const light = useMemo(() => TRAFFIC_LIGHTS[lightIndex], [lightIndex]);
function nextLight() {
if (lightIndex + 1 > TRAFFIC_LIGHTS.length - 1) {
setLightIndex(0);
} else {
setLightIndex(lightIndex + 1);
}
}
return (
<>
<button onClick={nextLight}>Next light</button>
<p>Light is: {light}</p>
<p>
You must
{light === 'red' && <span>STOP</span>}
{light === 'orange' && <span>SLOW DOWN</span>}
{light === 'green' && <span>GO</span>}
</p>
</>
);
}
Vue 3
<script setup>
import { ref, computed } from 'vue';
const TRAFFIC_LIGHTS = ['red', 'orange', 'green'];
const lightIndex = ref(0);
const light = computed(() => TRAFFIC_LIGHTS[lightIndex]);
function nextLight() {
if (lightIndex.value + 1 > TRAFFIC_LIGHTS.length - 1) {
lightIndex.value = 0;
} else {
lightIndex.value++;
}
}
</script>
<template>
<button @click="nextLight">
Next light
</button>
<p>Light is: {{ light }}</p>
<p>
You must
<span v-if="light === 'red'">STOP</span>
<span v-else-if="light === 'orange'">SLOW DOWN</span>
<span v-else-if="light === 'green'">GO</span>
</p>
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Lifecycle
On mount
Svelte
<script>
import { onMount } from 'svelte';
let pageTitle = '';
onMount(() => {
pageTitle = document.title;
});
</script>
<p>Page title is: {pageTitle}</p>
React
import { useState, useEffect } from 'react';
export default function PageTitle() {
const [pageTitle, setPageTitle] = useState('');
useEffect(() => {
setPageTitle(document.title);
});
return <p>Page title: {pageTitle}</p>;
}
Vue 3
<script setup>
import { ref, onMounted } from 'vue';
const pageTitle = ref('');
onMounted(() => {
pageTitle.value = document.title;
});
</script>
<template>
<p>Page title: {{ pageTitle }}</p>
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
On unmount
Svelte
<script>
import { onDestroy } from 'svelte';
let time = new Date().toLocaleTimeString();
const timer = setInterval(() => {
time = new Date().toLocaleTimeString();
}, 1000);
onDestroy(() => {
clearInterval(timer);
});
</script>
<p>Current time: {time}</p>
React
import { useState, useEffect } from 'react';
export default function Time() {
const [time, setTime] = useState(new Date().toLocaleTimeString());
const timer = setInterval(() => {
setTime(new Date().toLocaleTimeString());
}, 1000);
useEffect(() => {
return () => {
clearInterval(timer);
};
});
return <p>Current time: {time}</p>;
}
Vue 3
<script setup>
import { ref, onUnmounted } from 'vue';
const time = ref(new Date().toLocaleTimeString());
const timer = setInterval(() => {
time.value = new Date().toLocaleTimeString();
}, 1000);
onUnmounted(() => {
clearInterval(timer);
});
</script>
<p>Current time: {time}</p>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Component composition
Props
Svelte
<script>
import UserProfile from './UserProfile.svelte';
</script>
<UserProfile name="John" age={20} favouriteColors={['green', 'blue', 'red']} isAvailable />
<script>
export let name = '';
export let age = null;
export let favouriteColors = [];
export let isAvailable = false;
</script>
<p>My name is {name} !</p>
<p>My age is {age} !</p>
<p>My favourite colors are {favouriteColors.split(', ')} !</p>
<p>I am {isAvailable ? 'available' : 'not available'}</p>
React
import UserProfile from './UserProfile.jsx';
export default function App() {
return <UserProfile name="John" age={20} favouriteColors={['green', 'blue', 'red']} isAvailable />;
}
import PropTypes from 'prop-types';
export default function UserProfile({ name = '', age = null, favouriteColors = [], isAvailable = false }) {
return (
<>
<p>My name is {name} !</p>
<p>My age is {age} !</p>
<p>My favourite colors are {favouriteColors.split(', ')} !</p>
<p>I am {isAvailable ? 'available' : 'not available'}</p>
</>
);
}
UserProfile.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.isRequired,
favouriteColors: PropTypes.arrayOf(PropTypes.string).isRequired,
isAvailable: PropTypes.bool.isRequired,
};
Vue 3
<script setup>
import { ref } from 'vue';
import UserProfile from './UserProfile.vue';
const username = ref('John');
</script>
<template>
<input v-model="username">
<UserProfile :name="username" />
</template>
<script setup>
const props = defineProps({
name: {
type: String,
required: true,
default: '',
},
age: {
type: Number,
required: true,
default: null,
},
favouriteColors: {
type: Array,
required: true,
default: () => [],
},
isAvailable: {
type: Boolean,
required: true,
default: false,
},
});
</script>
<template>
<p>My name is {{ props.name }} !</p>
<p>My age is {{ props.age }} !</p>
<p>My favourite colors are {{ props.favouriteColors.split(', ') }} !</p>
<p>I am {{ props.isAvailable ? 'available' : 'not available' }}</p>
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Form input
Input text
Svelte
<script>
let text = 'Hello World';
</script>
<p>{text}</p>
<input bind:value={text} />
React
import { useState } from 'react';
export default function InputHello() {
const [text, setText] = useState('Hello world');
function handleChange(event) {
setText(event.target.value);
}
return (
<>
<p>{text}</p>
<input value={text} onChange={handleChange} />
</>
);
}
Vue 3
<script setup>
import { ref } from 'vue';
const text = ref('Hello World');
</script>
<template>
<p>{{ text }}</p>
<input v-model="text">
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Checkbox
Svelte
<script>
let isAvailable = false;
</script>
<input id="is-available" type="checkbox" bind:checked={isAvailable} />
<label for="is-available">Is available</label>
React
import { useState } from 'react';
export default function IsAvailable() {
const [isAvailable, setIsAvailable] = useState(false);
function handleChange() {
setIsAvailable(!isAvailable);
}
return (
<>
<input id="is-available" type="checkbox" checked={isAvailable} onChange={handleChange} />
<label htmlFor="is-available">Is available</label>
</>
);
}
Vue 3
<script setup>
import { ref } from 'vue';
const isAvailable = ref(true);
</script>
<template>
<input
id="is-available"
v-model="isAvailable"
type="checkbox"
>
<label for="is-available">Is available</label>
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Radio
Svelte
<script>
let picked = 'red';
</script>
<div>Picked: {picked}</div>
<input id="blue-pill" bind:group={picked} type="radio" value="blue" />
<label for="blue-pill">Blue pill</label>
<input id="red-pill" bind:group={picked} type="radio" value="red" />
<label for="red-pill">Red pill</label>
React
import { useState } from 'react';
export default function PickPill() {
const [picked, setPicked] = useState('red');
function handleChange(event) {
setPicked(event.target.value);
}
return (
<>
<input id="blue-pill" checked={picked === 'blue'} type="radio" value="blue" onChange={handleChange} />
<label htmlFor="blue-pill">Blue pill</label>
<input id="red-pill" checked={picked === 'red'} type="radio" value="red" onChange={handleChange} />
<label htmlFor="red-pill">Red pill</label>
</>
);
}
Vue 3
<script setup>
import { ref } from 'vue';
const picked = ref('red');
</script>
<template>
<div>Picked: {{ picked }}</div>
<input
id="blue-pill"
v-model="picked"
type="radio"
value="blue"
>
<label for="blue-pill">Blue pill</label>
<input
id="red-pill"
v-model="picked"
type="radio"
value="red"
>
<label for="red-pill">Red pill</label>
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Select
Svelte
<script>
let selectedColorId = 2;
const colors = [
{ id: 1, text: 'red' },
{ id: 2, text: 'blue' },
{ id: 3, text: 'green' },
{ id: 4, text: 'gray', isDisabled: true },
];
</script>
<select bind:value={selectedColorId}>
{#each colors as color}
<option value={color.id} disabled={color.isDisabled}>
{color.text}
</option>
{/each}
</select>
React
import { useState } from 'react';
const colors = [
{ id: 1, text: 'red' },
{ id: 2, text: 'blue' },
{ id: 3, text: 'green' },
{ id: 4, text: 'gray', isDisabled: true },
];
export default function ColorSelect() {
const [selectedColorId, setSelectedColorId] = useState(2);
function handleChange(event) {
setSelectedColorId(event.target.value);
}
return (
<select value={selectedColorId} onChange={handleChange}>
{colors.map((color) => (
<option key={color.id} value={color.id} disabled={color.isDisabled}>
{color.text}
</option>
))}
</select>
);
}
Vue 3
<script setup>
import { ref } from 'vue';
const selectedColorId = ref(2);
const colors = [
{ id: 1, text: 'red' },
{ id: 2, text: 'blue' },
{ id: 3, text: 'green' },
{ id: 4, text: 'gray', isDisabled: true },
];
</script>
<template>
<select v-model="selectedColorId">
<option
v-for="color in colors"
:key="color.id"
:value="color.id"
>
{{ color.text }}
</option>
</select>
</template>
Angular
Oops, missing snippet ! You can help us by contributing on Github.
Webapp features
Routing
Svelte
|-- routes/
|-- index.svelte // index page "/"
|-- about.svelte // about page "/about"
|-- __error.svelte // handle HTTP errors 404, 500,...
|-- __layout.svelte // global app layout
React
|-- pages/
|-- index.js // index page "/"
|-- about.js // about page "/about"
|-- 404.js // handle error HTTP 404 page not found
|-- 500.js // handle error HTTP 500
|-- _app.js // global app layout
https://remix.run/docs/en/v1/guides/routing
Vue 3
|-- pages/
|-- index.vue // index page "/"
|-- about.vue // about page "/about"
Angular
Oops, missing snippet ! You can help us by contributing on Github.