Skip to main content

webui-dev

Build interactive WebUI apps with compiled-template hydration, template syntax, component patterns, and CLI usage.

Source facts

Repository
microsoft/webui
Last source activity
September 9, 2026 at 01:08
Detected SKILL.md language
English
Stars
98
Forks
24

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
webui-dev
description
Build interactive WebUI apps with compiled-template hydration, template syntax, component patterns, and CLI usage.
# WebUI App Development Use this skill when building or modifying WebUI applications. ## Critical rules (memorize these) 1. **The template is the UI.** All structure lives in `.html`. Never `document.createElement`, `innerHTML`, `insertAdjacentHTML`, or `appendChild`. Show/hide with `<if>`, repeat with `<for>`. The only exception is mounting a lazily loaded component. 2. **CSS owns all styling and animation.** Never `el.style.x =`, `classList.toggle`, or `adoptedStyleSheets`. Bind `?data-active="{{expr}}"` and select `[data-active]` in CSS. Animate with `transition`, `@keyframes`, `@starting-style` - never `element.animate()` or a JS animation library. 3. **JavaScript is opt-in.** A component needs **no** `.ts` file unless it has an `@event`, a `w-ref` for an imperative API, a lifecycle hook, a fetch, or a public method API. `WebUIElement`, `@observable`, and `@attr` are optional - add them only when TypeScript reads/writes the value or it is public API. Otherwise the value belongs in the server state JSON. 4. **Use the web platform.** `<dialog>` over a div modal, `popover` over a JS dropdown, `<details>` over a JS accordion. Prefer `:has()`, `@container`, `color-mix()`, `light-dark()`, `content-visibility`. 5. **Every template binding must exist in the server state JSON.** Missing keys render empty, silently. 6. **HTML, CSS, TypeScript are separate files.** No JSX. No CSS-in-JS. No JS in templates. 7. **Unwrapped components default to Shadow; `--dom light` makes them global Light DOM while authored open wrappers stay Shadow.** A sole bare top-level `<template>` explicitly selects Light and is unwrapped even under the Shadow fallback. Light CSS uses ordinary selectors in its owning CSS tree. Use one sole top-level `<template shadowrootmode="open">` when the component needs native `<slot>` projection, Shadow encapsulation, CSS-heavy frequent restyling, root host events, or Shadow-only selectors such as `:host`. A `<slot>` and `:host` fail only in an effective Light component. 8. **Components inside `<for>` loops do NOT inherit loop variables.** Pass data via attributes. 9. **Text bindings are path lookups; comparisons belong in conditions.** `{{count}}` and `{{user.name}}` resolve a dotted state path - nothing else. `{{count > 0}}` is looked up as a key literally named `count > 0` and renders empty. Comparisons go in `<if condition="count > 0">` or `?active="{{section == 'guide'}}"`. Operators: `==`, `!=`, `<`, `>`, `<=`, `>=`, `&&`, `||`, `!`. **Forbidden everywhere:** ternary (`? :`), function calls, arithmetic (`items.length - 1` resolves as a path and silently fails - send a precomputed `lastIndex`), mixing `&&` with `||`, more than 5 logical operators. 10. **`w-ref` requires braces.** `w-ref="{inputEl}"`, never `w-ref="inputEl"` - non-braced fails the build with `invalid-w-ref`. Use it only for imperative APIs (focus, scroll, `showModal`), never to read state. 11. **`@attr({ mode: 'boolean' })` for true/false.** Present = true, absent = false. Never use string `"false"`. ## Quick reference Most components need only HTML and CSS: ```html <!-- user-card.html - no .ts file --> <h2>{{user.name}}</h2> <if condition="user.isAdmin"><span class="badge">Admin</span></if> ``` Add a class only when something interactive happens: ```typescript import { WebUIElement, attr, observable } from '@microsoft/webui-framework'; export class MyComponent extends WebUIElement { @attr label = ''; // set by a parent template @attr({ mode: 'boolean' }) disabled = false; @observable count = 0; // mutated by increment() inputEl!: HTMLInputElement; // populated by w-ref="{inputEl}" increment(): void { this.count += 1; } onKeydown(e: KeyboardEvent): void { if (e.key === 'Enter') this.submit(); } } MyComponent.define('my-component'); ``` ```bash webui build ./src --out ./dist --plugin=webui webui serve ./src --state ./data/state.json --plugin=webui --watch ``` ## Full reference The complete guide covering all template syntax, styling and animation rules, anti-patterns, routing, and a pre-flight checklist: **[docs/ai.md](/docs/ai.md)** Read that file before generating any WebUI code.
View on GitHub