Reference

Targets

What each of the seven targets writes, the capability matrix that declares where a framework differs, and how Angular hosts a component.

Unframework compiles each component to seven targets. Each one writes a component in its framework's own format, and imports nothing but its framework.

TargetFileComponent
ReactProductTile.tsxA function component
VueProductTile.vueA single-file component with <script setup lang="ts">
SvelteProductTile.svelteA component in runes mode, with <script lang="ts">
Angularproduct-tile.tsA component class with signal inputs and an inline template
SolidProductTile.tsxA function component
QwikProductTile.tsxA component$
AstroProductTile.astroA component with its props in the frontmatter

Props shows the seven files for one component.

Capabilities

A capability is a feature a component can use: a kind of node, a kind of attribute, or something a framework does at run time. Each target declares, for every capability, how it supports it:

  • native: the framework has the feature, and the output uses it;
  • emulated: the output adds a small inline helper, named in the cell, because the framework lacks the feature;
  • unsupported: the framework renders the feature differently, or not at all. The compiler reports UF4001 at the feature's first use, with the target's reason, and the cell sets its severity.

So a difference between frameworks is declared here, never found only in a test.

CapabilityWhat it coversReactVueSvelteAngularSolidQwikAstro
elementHTML elementsnativenativenativenativenativenativenative
textStatic textnativenativenativenativenativenativenative
static-attributeAttributes with a literal valuenativenativenativenativenativenativenative
listboxA <select> shown as a single-selection list boxnativeunsupportednativenativenativenativenative
interactivityEvent handlers and updates in the browsernativenativenativenativenativenativeunsupported
propsA component with propsnativenativenativenativenativenativenative
interpolationExpressions rendered as textnativenativenativenativenativenativenative
conditionalc ? <A /> : <B /> and c && <A />nativenativenativenativenativenativenative
list.map with a key: the items' content and ordernativenativenativenativenativenativenative
fragmentA root fragment with several nodesnativenativenativenativenativenativenative
bound-attributeAttributes bound to an expressionnativenativenativenativenativenativenative
class-bindingA class of names, toggles and expressionsemulated cxnativenativenativeemulated cxnativenative
style-bindingA style of static and bound declarationsnativenativenativenativenativenativenative
attribute-spreadA spread of an object whose type declares its keysnativenativenativenativenativenativenative
svgAn <svg> and the SVG inside itnativenativenativenativenativenativenative

The cells that are not native:

  • React, class-binding: React's className takes one string, so an inline helper, cx, joins the static names, toggles and dynamic parts.
  • Solid, class-binding: Solid's class takes one string, so an inline helper, cx, joins dynamic parts with the static names and toggles. Static names and toggles alone print as class and classList.
  • Vue, listbox (an error): Vue's client sets multiple but not size before it inserts the options, so it selects the first option, as a drop-down does, where HTML selects none.
  • Astro, interactivity (for information): Astro components render on the server only, so their event handlers are inert.

Every other difference between the frameworks is either handled by the target that has it, or rejected for every target by the compiler, with a code that names the framework. Attributes and Templates list them.

The Angular host

Angular renders every component inside a host element, which wraps the template's root. The other frameworks render the root directly. Unframework gives each Angular component an element selector, uf- and its name in kebab case, and styles its host display: contents:

product-tile.ts
@Component({
  selector: "uf-product-tile",
  host: { style: "display: contents" },
  preserveWhitespaces: false,

A consumer writes <uf-product-tile>, Angular's ordinary element syntax. display: contents keeps the host out of layout, so the component's geometry and pixels match the other targets', and its accessibility tree is the same. The template holds the whole render tree: a single root, the roots of a root fragment, and the conditionals and lists beside them all render inside the one host.

Attribute selectors, which make the consumer's own element the host, are deferred to M3, with composition. Until then:

  • a component whose root must sit directly inside its parent, such as an <li> in a consumer's list or a <tr> in a consumer's table, cannot be written for Angular;
  • fallthrough attributes and slots, which need the host or a helper directive, land in M3.

The decisions behind this page are ADR-0010, ADR-0015 and ADR-0033.

Copyright © 2026