diff --git a/active-rfcs/0046-patterned-template.md b/active-rfcs/0046-patterned-template.md new file mode 100644 index 00000000..6363515a --- /dev/null +++ b/active-rfcs/0046-patterned-template.md @@ -0,0 +1,784 @@ +- Start Date: 2026-03-05 +- Target Major Version: ? +- Reference Issues: N/A +- Implementation PRs (Draft reference implementation): [compiler / SSR / Vapor](https://github.com/vuejs/core/pull/15531), [language-tools](https://github.com/vuejs/language-tools/pull/6207), [docs](https://github.com/vuejs/docs/pull/3465) + +# Summary + +Introduce `v-match` and `v-when` for declarative pattern-based conditional rendering in Vue templates. + +`v-match` evaluates a subject expression once. Each direct `v-when` child declares a pattern, optional bindings (including object and array rest), and an optional guard. Branches are checked from top to bottom, only the first matching branch renders, and no fallthrough is possible. Template type checking requires exhaustive coverage, with `_` available as the fallback pattern. + +The initial syntax keeps `v-when` in its long form. Shorthand candidates and their trade-offs are recorded below for future discussion. + +The proposed syntax intentionally follows the vocabulary of the TC39 ECMAScript Pattern Matching proposal (`match` / `when`, pattern guards, declaration bindings) while also catching up with Flow's shipped `match` feature (`const` variable declaration patterns, `if` guards, `_` wildcard, `|` alternatives, `as` bindings, and exhaustiveness-aware tooling). + +# Basic example + +```vue + + + +``` + +The above is equivalent in behavior to a `v-if` / `v-else-if` chain that first evaluates `result`, checks each branch in order, introduces branch-local template bindings such as `article` and `error`, and renders the fallback only if no previous branch matched. + +# Motivation + +## Chained `v-if` is repetitive for one subject + +When rendering different content based on a single reactive value, developers currently repeat the same expression in every branch: + +```vue + +``` + +This has several drawbacks: + +1. The discriminant expression is repeated in every branch. +2. Branches that conceptually belong to one match are only implicitly grouped by adjacency. +3. Nested data has to be re-addressed manually instead of being bound where it is matched. +4. Type tooling has to recover intent from arbitrary boolean expressions. + +`v-match` makes the subject explicit, and `v-when` makes each branch an arm of the same match. + +## Vue code increasingly models UI state as tagged data + +Vue applications commonly consume typed state from composables, loaders, data-fetching libraries, state stores, routers, and RPC clients. These values are often modeled as discriminated unions or tagged objects: + +```ts +type RemoteData = + | { status: 'idle' } + | { status: 'loading' } + | { status: 'success'; data: T } + | { status: 'error'; error: E } +``` + +Templates need an ergonomic way to render these states without repeatedly indexing into the same object and without losing branch-specific type information. + +## Prior art is converging on patterns plus bindings + +- The [TC39 ECMAScript Pattern Matching proposal](https://github.com/tc39/proposal-pattern-matching) uses `match` expressions with `when` arms, declaration patterns such as `const status`, rest binding patterns, and guard patterns. +- [Flow's `match`](https://flow.org/en/docs/match/) has shipped with object, array, wildcard, `const`, `|`, `as`, instance, guard, exhaustiveness, and unused-pattern checks. +- Rust, Swift, Kotlin, Scala, F#, Python, and Elixir all demonstrate that pattern matching is most valuable when it can both test a shape and bind useful parts of the matched value. + +This RFC does not attempt to add JavaScript pattern matching to Vue. It proposes a template-level feature that borrows the parts that map cleanly to rendering: arm syntax, structural patterns, branch-local bindings, guard conditions, and type-tooling hooks. + +# Detailed design + +## Recommended syntax: `v-match` / `v-when` + +```html + +``` + +- `v-match` evaluates the subject expression. +- `v-when` declares a pattern arm. +- `v-when="_"` declares an unconditional fallback arm. +- An optional `if ()` suffix acts as a branch guard. + +The name `v-when` is recommended over the previous `v-case` direction because it directly mirrors TC39's `match (...) { when ... }` vocabulary and avoids suggesting JavaScript `switch` fallthrough behavior. + +## SFC top-level template + +An SFC may place `v-match` directly on its top-level `