Angular Formatter

Paste a component and the class, the inline template and the styles array each get formatted by their own rules. Structural directives, property and event bindings, template references and the control flow blocks from Angular 17 come back exactly as you wrote them, on the right line.

Angular formatting workspace

nothing loadedFormat with Ctrl + Enter, or drop a .ts or .html file on the left pane
Read as
Indent
Wrap at
Your Angular0 lines
Formattedwaiting for input
Lines out0
Elements0
Bindings0
Event handlers0
Control flow0
Tags wrapped0
What the parser noticed

    An Angular component holds three languages, and only one of them is TypeScript

    Open a component file and you are reading a decorated class, an HTML template with Angular syntax layered over it, and a block of CSS, all inside one pair of braces. Feed the whole thing to a JavaScript beautifier and the class comes out clean while the template stays welded into a single line, because the beautifier sees a string and leaves strings alone. This page splits the file first, then hands each piece to rules written for that piece.

    The class

    Decorators, members and lifecycle hooks go through a JavaScript pass tuned for Angular. Generic type arguments are masked before the pass runs, so Observable<User | null> does not come back split into a row of comparison operators.

    The template

    Markup inside the template backticks, or a whole standalone file, is parsed into a tree of elements, text and control flow blocks. Bindings, structural directives and template references survive character for character.

    The styles

    Rules in the styles array are formatted as CSS, then pushed back in at the indent of the property holding them, rather than flattened against the left margin the way a single pass leaves them.

    What a plain JavaScript beautifier does to your template

    The difference shows up on the first component you paste. A beautifier walks tokens, and a template literal is one token to it. Everything between the backticks is copied through untouched, so a template written on one line stays on one line no matter how you set the options.

    A JavaScript beautifier
    template: `<div class="row" *ngFor="let m of members"><span>{{m.name}}</span></div>`
    This page
    template: `
    <div class="row" *ngFor="let m of members"><span>{{ m.name }}</span></div>`

    The template printer, rule by rule

    Control flow blocks are parsed, not treated as loose text

    Angular 17 moved branching out of directives and into template syntax. A formatter with no knowledge of the blocks reads @if (open) { as a run of text and the matching brace as more text, so both land wherever they started. Here the blocks build real nodes, children indent under them, and a closing brace followed by a continuation joins onto one line.

    Pasted in
    @if (user()) {<p>Hi</p>} @else {<a routerLink="/login">Sign in</a>}
    Formatted
    @if (user()) {<p>Hi</p>} @else {<a routerLink="/login">Sign in</a>}

    The same treatment covers @for with its @empty branch, @switch with @case and @default, and @defer with @placeholder, @loading and @error. Braces belonging to interpolation are recognised first, so an expression sitting inside a block never gets mistaken for the end of it.

    Tags wrap by measurement, not by attribute count

    Angular tags run long. One button carries a class list, a disabled binding, a click handler and a test id before anybody calls the code messy. The formatter builds the opening tag, measures the finished line against your wrap column of 80, 100 or 120 characters, and splits one attribute per line only when the line runs past it. A tag with a single attribute never splits, since <div class="card"> spread over three lines helps nobody.

    Why the closing bracket stays attached

    When a tag splits, the > rides on the last attribute line rather than dropping to a line of its own. Both styles are in wide use. This one keeps the vertical cost of wrapping down, which matters on a template where half the elements carry four bindings.

    The list beside the output reads the tree you pasted

    Formatting and reviewing are separate jobs, so nothing in this list edits your code. While the parser walks the template it records patterns worth a second look, groups repeats, and counts them:

    Nothing leaves the tab

    Parsing, formatting and rendering all run in your browser. Disconnect after the page loads and every button keeps working. Angular components pasted into web tools carry internal API paths, feature flag names and route structures for software that has not shipped yet, so a round trip through somebody else's server buys nothing worth the exposure.

    Where this formatter stops

    Questions that come up while formatting Angular

    Templates, bindings, control flow blocks and what a browser based formatter refuses to touch.

    Will formatting change how my component behaves?

    Indentation and line breaks in a template carry no meaning to Angular, so the rendered result stays the same. Attribute values are copied through untouched apart from collapsing runs of whitespace inside bindings, and text inside pre and textarea elements is preserved exactly. The one real risk sits with input that already contains a syntax error, since no compiler runs here to catch it. Build the project once after pasting the output back.

    Why did my template come back untouched?

    Most likely the component points at an external file through templateUrl, so there is no markup in the class to format. The status line says so when that happens. Open the .html file, paste that in instead, and the page switches to template mode on its own. The same applies to styleUrls, since only styles written inline in the decorator are formatted.

    Does it understand the control flow blocks added in Angular 17?

    Yes. The if, for, switch, defer and their continuation branches are parsed as real nodes rather than text, so children indent one level under them and a closing brace followed by an else or an empty branch joins onto a single line. Interpolation braces are recognised before block braces, which is what keeps an expression inside a block from being read as the end of it.

    What happens to structural directives and bindings?

    They are treated as ordinary attribute names, so the star prefix, the square brackets, the parentheses and the banana in a box syntax all pass through as written. Values inside a binding have runs of whitespace collapsed to single spaces and pipe operators padded. Plain HTML attributes keep their values byte for byte, because prose in a title attribute depends on the spacing you gave it.

    Is my code sent anywhere?

    No. The parser, the printer and the editors are all JavaScript running in your tab, and the page makes no network request after it loads. Turn your connection off once the page appears and every button still works. This matters for Angular in particular, since pasted components tend to carry internal API routes, feature flag names and the shape of software that has not launched yet.

    How is this different from running Prettier?

    Prettier parses Angular templates with the real grammar, reflows text, and enforces one style across a repository through a CI check. This page reads the markup as a tree and prints it back with rules covering indentation, wrapping and spacing, which stops short of rewriting expressions. For a project under version control, install Prettier. For a snippet somebody dropped into a chat thread, opening a page beats setting up a toolchain.

    Why are some tags split across lines and others not?

    The finished opening tag is measured against the wrap column you picked, 80, 100 or 120 characters. Only tags that run past it split, and only when they carry more than one attribute. That keeps a short tag on one line while a button with a class list, a disabled binding and a click handler gets one attribute per line. Drop the wrap column to 80 to see more tags split.

    Does it mangle my TypeScript generics?

    No, and that took specific work. A general JavaScript beautifier reads the angle brackets in a generic as comparison operators and pads them out, which turns a clean return type into something unreadable. Generic arguments are masked before the JavaScript pass and restored afterwards, so nested types come back intact while genuine comparisons in your code still get normal operator spacing.

    What is the list beside the output for?

    It reports patterns the parser met while walking your template, grouped and counted. Two entries are build failures: a for block with no track expression, and two structural directives on one element. The rest are worth a look rather than urgent, covering ngFor without trackBy, innerHTML bindings, native onclick attributes, click handlers on elements keyboard users cannot reach, and images with no alt text. Nothing on the list edits your code.

    Can I format a standalone template file?

    Yes. Paste the markup or drop the .html file onto the left pane and detection switches to template mode, which you can also force with the Read as control. Download then writes the result back out as an .html file, and the editor switches its highlighting to match. Files above 2 MB are refused, since a browser editor holding that much text stops responding.