Signals in JavaScript: TC39 Wants to Make Reactivity a Native Language Standard
Hello HaWkers, a proposal is shaking up the JavaScript world: Signals could become an official part of the language. This means native reactivity, without needing frameworks.
Angular, Vue, Solid, Svelte - all already use Signals. But React doesn't. Let's understand this divide and what it means for the future.
What Are Signals
Understanding the fundamental concept.
Primitive Reactivity
Signals are reactive values:
// Current TC39 proposal
const count = new Signal.State(0);
// Read the value
console.log(count.get()); // 0
// Update the value
count.set(1);
// Derived computation
const double = new Signal.Computed(() => count.get() * 2);
console.log(double.get()); // 2Why This Matters
Difference from traditional state:
Without Signals (manual state):
let count = 0;
let double = count * 2;
// Problem: double doesn't update automatically
count = 5;
console.log(double); // Still 0! Not reactiveWith Signals (reactive):
const count = new Signal.State(0);
const double = new Signal.Computed(() => count.get() * 2);
count.set(5);
console.log(double.get()); // 10 - Updates automatically!
How Frameworks Use Signals
Each framework has its implementation.
Vue 3
Signals under the name "ref":
import { ref, computed } from 'vue';
// State signal
const count = ref(0);
// Computed signal
const double = computed(() => count.value * 2);
// Template reacts automatically
<template>
<button @click="count++">
{{ count }} x 2 = {{ double }}
</button>
</template>Angular
Official Signals since Angular 16:
import { signal, computed, effect } from '@angular/core';
// State signal
const count = signal(0);
// Computed signal
const double = computed(() => count() * 2);
// Side effect
effect(() => {
console.log(`Count is now: ${count()}`);
});
// Update
count.set(5);
count.update(n => n + 1);Solid.js
Signals are the framework's core:
import { createSignal, createMemo, createEffect } from 'solid-js';
const [count, setCount] = createSignal(0);
const double = createMemo(() => count() * 2);
createEffect(() => {
console.log(`Count: ${count()}, Double: ${double()}`);
});
// JSX is reactive at expression level
<button onClick={() => setCount(c => c + 1)}>
{count()} x 2 = {double()}
</button>Svelte 5 (Runes)
New syntax with runes:
<script>
let count = $state(0);
let double = $derived(count * 2);
$effect(() => {
console.log(`Count is ${count}`);
});
</script>
<button onclick={() => count++}>
{count} x 2 = {double}
</button>
Why React Doesn't Use Signals
The controversy explained.
Different Philosophy
React chose another path:
React's model (Virtual DOM):
function Counter() {
const [count, setCount] = useState(0);
const double = count * 2; // Recalculates on every render
return (
<button onClick={() => setCount(c => c + 1)}>
{count} x 2 = {double}
</button>
);
}
// Entire component re-renders when count changesSignals model (Granular reactivity):
function Counter() {
const count = signal(0);
const double = computed(() => count() * 2);
return (
<button onClick={() => count.set(c => c + 1)}>
{count()} x 2 = {double()}
</button>
);
}
// Only the expressions {count()} and {double()} updateTrade-offs
Each approach has advantages:
| Aspect | React Hooks | Signals |
|---|---|---|
| Performance | Re-render component | Granular update |
| Mental model | Simple and predictable | More complex |
| Debug | React DevTools | More difficult |
| Bundle size | Larger | Smaller |
| Server rendering | Mature | Evolving |
React's Official Position
What the React team says:
"Signals are performance optimization, not a new paradigm. React prefers to keep the mental model simple and optimize under the hood."
React's strategy:
- React Compiler (former React Forget)
- Automatic memoization
- Concurrent rendering
- Server Components
The TC39 Proposal
What's being standardized.
Current Status
Committee progress:
Stage 1 (Proposal):
- Approved in April 2024
- Polyfill available
- Experimental implementations
- Active discussions
Proposed API
Planned interface:
// State signal
const counter = new Signal.State(0);
// Reading
counter.get(); // 0
// Writing
counter.set(1);
// Computed signal
const doubled = new Signal.Computed(() => counter.get() * 2);
// Read only
doubled.get(); // 2
// Watcher for effects
const watcher = new Signal.subtle.Watcher(() => {
// Notifies when observed signals change
console.log("Something changed!");
});
watcher.watch(doubled);Why In The Browser
Benefits of having it native:
1. Interoperability:
// Vue signals working with Angular
import { ref } from 'vue';
import { signal } from '@angular/core';
// Today: Incompatible
// With standard: Interchangeable2. Performance:
- Native C++ implementation
- Engine optimizations
- Less abstraction overhead
- Better DOM integration
3. Consistency:
- Same API across all frameworks
- Code portability
- Unified documentation
- Less fragmentation
Impact On Frameworks
What changes for each one.
Vue
Easier migration:
// Vue 3 today
import { ref, computed } from 'vue';
const count = ref(0);
// Vue future (possible)
const count = new Signal.State(0);
// Vue adds only convenience layersAngular
Already prepared:
// Angular today already has similar API
import { signal, computed } from '@angular/core';
// Migration to native would be transparent
// Mainly performance gainsSolid
Validates the approach:
// Solid already uses very similar API
// Would be almost drop-in replacement
// Ryan Carniato is involved in the proposalReact
Pressure to adapt:
Possible scenarios:
- React ignores and keeps current approach
- React creates compatibility layer
- React offers optional "signals" mode
- New dominant framework emerges
Performance In Practice
Real benchmarks.
Framework Comparison
10,000 item update test:
| Framework | Time (ms) | Memory (MB) |
|---|---|---|
| Vanilla + Signals | 12 | 8 |
| Solid.js | 14 | 10 |
| Vue 3 | 18 | 12 |
| Svelte 5 | 16 | 11 |
| Angular 19 | 22 | 15 |
| React 19 | 45 | 28 |
When Signals Shine
Ideal use cases:
Dashboards with lots of data:
// With Virtual DOM: Everything re-renders
// With Signals: Only changed cells update
const cells = Array(10000).fill(null).map(() =>
new Signal.State(Math.random())
);
// Update one cell: O(1) with Signals
cells[5000].set(0.5);Complex forms:
// Reactive and granular validation
const email = new Signal.State('');
const isValid = new Signal.Computed(() =>
email.get().includes('@')
);
// Only the validation indicator updatesAnimations and games:
// 60fps updates
const position = new Signal.State({ x: 0, y: 0 });
// Minimum overhead per frame
requestAnimationFrame(() => {
position.set({ x: position.get().x + 1, y: 0 });
});
Using Signals Today
How to experiment now.
Official Polyfill
Installation and usage:
npm install signal-polyfillimport { Signal } from 'signal-polyfill';
const count = new Signal.State(0);
const double = new Signal.Computed(() => count.get() * 2);
// Works in any environment
console.log(double.get()); // 0
count.set(5);
console.log(double.get()); // 10Production-Ready Frameworks
Options for production:
If you want Signals today:
- Solid.js - Purest in Signals
- Vue 3 - Signals as "refs"
- Angular 17+ - Official Signals
- Svelte 5 - Runes (Signals with syntax)
Standalone libraries:
- Preact Signals
- @preact/signals-core
- MobX (similar concept)
The Future
Where we're headed.
Likely Timeline
Realistic expectations:
2026:
- Stage 2 of proposal
- Stable polyfills
- Browser experiments
2027:
- Stage 3 (candidate)
- Native implementations begin
- Frameworks adapting
2028+:
- Stage 4 (finalized)
- Available in browsers
- New era of frameworks
Career Impact
What developers should do:
Short term:
- Understand the Signals concept
- Experiment in personal projects
- Continue using your current framework
Medium term:
- Follow the TC39 proposal
- Evaluate Solid/Vue/Angular
- Prepare for changes
Long term:
- Signals will be base knowledge
- Frameworks will converge
- New architectures will emerge
Conclusion
Signals represents a possible unification of the JavaScript ecosystem. Whether the proposal is approved or not, the concept already dominates modern frameworks - Angular, Vue, Solid, Svelte all converge on this approach.
React continues on its own path, but pressure increases. Time will tell if Virtual DOM remains competitive or if Signals becomes the standard.
For developers, the advice is: understand the concept now. Whatever the outcome, granular reactivity is a clear trend.
If you want to strengthen your JavaScript foundation, check out our article on ES2026 and Temporal API to see other important language news.
Let's go! 🦅
💻 Master JavaScript for Real
The knowledge you gained in this article is just the beginning. Understanding fundamental concepts like reactivity requires a solid language foundation.
Invest in Your Future
I've prepared complete material for you to master JavaScript:
Payment options:
- 1x of $4.90 no interest
- or $4.90 at sight

