angular/playground
Angular Playground for Components, Services and Signals
Answer a small Angular question in the time it takes to ask it — a service injected, a signal propagating, an error naming its token, all with the console sitting beside the running app.
import { Component, signal, effect } from '@angular/core'
@Component({ selector: 'demo', template: `
<button (click)="n.set(n() + 1)">{{ n() }}</button>
` })
export class Demo {
n = signal(0)
log = effect(() => console.log('n is', this.n()))
}
01 platform
Why Angular questions are best answered by running them
Angular's hard parts are wiring questions — which injector resolved this, why change detection did not fire, what this token is. Dependency injection and signals are the two most searched of them, and neither answers well on paper.
-
Injector scope, demonstrated in seconds
Move a service from
providedIn: 'root'to a component'sprovidersarray and watch the constructor fire once per component instead of once per app. That is the whole concept, in one edit. -
NullInjectorErrorreproduced deliberatelyAngular's most-searched error is easiest to understand when you cause it on purpose. Remove a provider, read the token in the message, put it back.
-
Signal propagation you can watch
An
effectlogging its own dependencies shows exactly when a computed re-evaluates and when it serves a cached value. -
No
ng newbetween you and the questionThe scaffold wait is the reason small Angular questions get answered by guessing instead of by testing. There is no scaffold here.
02 pipeline
Testing a service, start to finish
Four moves. This is what checking an Angular service costs here, against the several minutes a CLI scaffold costs before the first line of your own code.
-
Write the service
An
@Injectableclass in its own file, with aprovidedInscope. Two files, because a service that only exists inside one component is not the thing you are testing. -
Inject it
inject(MyService)in a component field. The injector resolves at construction, and a log in the service constructor tells you how many instances actually exist. -
Change the scope
Move the provider between the root and the component and watch the instance count change. This is the experiment that makes DI hierarchies concrete.
-
Share the result
Send the link. Whoever opens it gets the same providers, the same log output and the same reproduction — what an issue thread actually needs.
03 features
What the playground gives an Angular experiment
Everything below matters for testing Angular behavior specifically, rather than for building an application.
-
The real injector
Provider scopes,
InjectionToken, multi-providers andinject()all behave as Angular implements them, so what you learn transfers to a production app unchanged. -
Angular's own dev-mode errors
NullInjectorError,ExpressionChangedAfterItHasBeenCheckedand template binding errors arrive with Angular's wording, which is what makes them searchable. -
Signals and the control flow
signal,computed,effectand the@if/@forblocks compile as they do locally, so the reactivity you test is the reactivity you will ship. -
RxJS operators in full
Subjects, operators and the
asyncpipe work against the real library, so a marble-diagram question can be answered by running it. -
Real npm packages
Angular Material, NgRx or a date library install and import by name, because a mock answers a question you did not ask.
-
A link that reproduces
Share the project and it opens as you left it — usable on a GitHub issue rather than as a screenshot.
04 deep dive
Watching a signal propagate
Angular signals replaced Zone.js checking everything with values that notify their own dependents. That is a mental-model change, and models are learned by watching rather than reading.
effect shows you its own dependencies. Log inside one and the console tells you exactly which signal change triggered the re-run — including the ones you did not expect.
computed caching is observable. Read a computed twice with a log inside it; it fires once. The cache stops being a claim and becomes a thing you saw.
Zoneless change detection changes the timing. Without Zone.js patching async APIs, an update happens because a signal was set rather than because a timer fired. Watching that is how the difference stops being abstract.
toSignal bridges the old model. An existing Observable becomes a signal without rewriting the stream, which is how a real migration proceeds one piece at a time.
- effect
- dependency tracking
- computed
- cached, observable
- change detection
- zoneless
- bridge
- toSignal
const n = signal(1)
const doubled = computed(() => {
console.log('computed ran')
return n() * 2
})
effect(() => console.log('effect', doubled()))
05 workflow
An injection failure, and the fix
One real sequence, from opening the tab to understanding an error. The console sits beside the app, so nothing here required opening devtools.
- open → Angular playground
- JIT compile 18ms · bootstrapped
- [log] UserService constructed
- edit → remove providedIn
- NullInjectorError: No provider for UserService!
- R3Injector.get — user-card.component.ts:9
- add to providers → save
- recompiled · 1 instance per component
-
The token is named
Angular's injector errors say which token failed to resolve, which turns a vague failure into a one-line fix once you know where to look.
-
Instance counts are visible
A log in a constructor is the cheapest possible instrumentation for provider scope, and it answers the question no diagram does.
-
Recovery is one save
Fix the provider and save. The app re-bootstraps in place; there is no dev server to restart.
06 deep dive
When injection or change detection goes wrong
Two categories cover most Angular debugging, and both are far easier to see than to reason about.
Injection errors point at a token and a file. NullInjectorError names what could not be resolved and where it was requested, so the search starts in the right place.
Change detection surprises have a name. ExpressionChangedAfterItHasBeenChecked is Angular telling you a value moved during the check, and reproducing it deliberately is the fastest way to stop fearing it.
Angular DevTools attaches normally. The browser extension inspects the real component tree and the injector graph, because the preview is a genuine Angular application rather than a picture of one.
- injection
- token + file
- change detection
- named errors
- devtools
- Angular DevTools works
- restart
- never needed
NullInjectorError: R3InjectorError(Standalone[Demo])[UserService]:
NullInjectorError: No provider for UserService!
requested by user-card.component.ts:9:23
07 ecosystem
One project, several frameworks
An Angular component can sit beside a .vue file and a Python script; the compiler is chosen per file, not per project.
08 languages
Every language the editor understands
Highlighting and IntelliSense cover 70+ languages. These are the ones XCODX also compiles or executes for you.
Compiled in your browser11
Zero build step. Transform runs on a Web Worker, so typing never blocks.
- JSX
- TSX
- TypeScript
- Vue SFC
- Svelte
- Angular (JIT)
- SolidJS
- SCSS
- Sass
- Less
- Pug
Rendered natively8
Straight to the live preview, no transform in the way.
- HTML
- CSS
- JavaScript
- JSON
- Markdown
- Jupyter (.ipynb)
- SVG
- YAML
Executed on demand22
70+ languages run through a self-hosted Piston engine. stdout, stderr, images and tracebacks land in the console.
- Python
- Java
- C
- C++
- C#
- Go
- Rust
- Ruby
- PHP
- Kotlin
- Swift
- Lua
- Scala
- Perl
- Haskell
- Elixir
- Dart
- R
- Julia
- SQLite
- Bash
- PowerShell
09 questions
Using the Angular playground — common questions
Questions about the fast loop specifically.
How is this different from a StackBlitz Angular starter?
StackBlitz runs a real Node process in the browser, which buys you the CLI and a dev server. This trades those away for an instant start and a compiler that runs entirely on your device — no container to boot, and it keeps working offline.
Why does my service construct more than once?
Provider scope. providedIn: 'root' gives one instance for the whole application; the same service listed in a component's providers array gives one per component instance. Put a log in the constructor and the answer becomes obvious in a few seconds.
Can I reproduce a NullInjectorError deliberately?
Yes, and it is one of the better uses for a playground. Remove a provider, read the token Angular names in the message, then put it back. Causing the error on purpose is how it stops being frightening.
Do signals and effects work here?
Yes. signal, computed and effect run against Angular's own reactivity, and the built-in @if and @for blocks read them in templates directly. An effect logging its dependencies is the fastest way to see when things re-evaluate.
Does RxJS still work if I prefer Observables?
Fully. Operators, subjects and the async pipe behave as they do locally, and toSignal and toObservable let you mix both models in the same component rather than committing to one.
Does Angular DevTools work?
Yes. The browser extension attaches to the preview and inspects the real component tree and injector graph, because the preview is a genuine Angular application.
Can I test a component that uses the router?
Yes. Install @angular/router, provide it in the bootstrap and navigate in the preview. Route guards and resolvers run as they would in a local project.
Is there a limit on how long a playground lasts?
No. Projects live in your browser rather than on a server with a retention policy, so an experiment you left open last month is still there.
Does the playground work if I lose my connection?
Once loaded, yes. XCODX installs as a Progressive Web App and the JIT compiler runs on your device, so editing and compiling keep working offline. Only installing a new package needs the network.
Do I need to install anything to use XCODX Studio?
No. XCODX Studio is a browser-based IDE — the editor, the compilers and the preview all run client-side. There is no download, no package manager to set up and no configuration file to write. Opening the editor is the whole setup step.
Where is my code stored?
In your own browser. Projects, file history and Git objects live in local storage on your device and are never uploaded to a server. That also means XCODX works offline: it is a Progressive Web App, so you can install it and keep coding with no connection.
Is XCODX Studio free?
Yes. The editor, the live preview, the 70+ language runtimes, npm installs, Git and the integrated terminal are all free to use.
Can I use XCODX on a tablet or Chromebook?
Yes. The editor is a responsive web app, so a Chromebook, an iPad or an Android tablet gets the same compilers and the same preview a laptop does — there is no desktop-only build, because there is no build to install at all. The layout adapts to the screen rather than shrinking a desktop UI into it.
Can I export a project or move it to my own machine?
Yes. Export the whole project as a zip with its folder structure intact and open it locally, or commit it and push. It is ordinary source on disk from that point on — no proprietary format and no lock-in, which is also why importing an existing repository from GitHub works the same way in reverse.
Nothing to install
Open the Angular playground
A component compiled and a service injected in seconds, with the console beside it and a link to hand over when it does something interesting.
