Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/skills/testing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,9 @@ The test server (`fixture-render.ts`) auto-discovers fixtures with `src/index.ht
2. Create `fixtures/<name>/src/test-widget/test-widget.html` — component template:

```html
<template shadowrootmode="open">
<span class="label">{{label}}</span>
<span class="count">{{count}}</span>
<button class="inc" @click="{increment()}">+</button>
</template>
<span class="label">{{label}}</span>
<span class="count">{{count}}</span>
<button class="inc" @click="{increment()}">+</button>
```

3. Create `fixtures/<name>/state.json` — initial state:
Expand Down
6 changes: 2 additions & 4 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,8 @@ pub struct WebUIFragmentOutlet {}

Components use `<outlet />` in their templates to declare insertion points:
```html
<template shadowrootmode="open">
<h1>Title</h1>
<main><outlet /></main>
</template>
<h1>Title</h1>
<main><outlet /></main>
```

**Route declaration:** Routes are declared as nested `<route>` elements in the entry HTML.
Expand Down
6 changes: 2 additions & 4 deletions docs/guide/ai.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,8 @@ In the TypeScript class: `searchInput!: HTMLInputElement;`

```html
<!-- Parent component template -->
<template shadowrootmode="open">
<nav>...</nav>
<main><outlet /></main>
</template>
<nav>...</nav>
<main><outlet /></main>
```

## Component Class
Expand Down
20 changes: 8 additions & 12 deletions docs/guide/concepts/directives/route.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,11 @@ Components that have child routes use `<outlet />` to mark where the matched chi

```html
<!-- app-shell.html -->
<template shadowrootmode="open">
<header><nav-bar></nav-bar></header>
<main>
<outlet />
</main>
<footer></footer>
</template>
<header><nav-bar></nav-bar></header>
<main>
<outlet />
</main>
<footer></footer>
```

The shell (header, footer) persists across all routes. Only the content at `<outlet />` changes.
Expand All @@ -54,11 +52,9 @@ Routes can be nested to any depth. Each level's component uses `<outlet />` for

```html
<!-- contacts-page.html -->
<template shadowrootmode="open">
<h2>Contacts</h2>
<div class="contact-list">...</div>
<outlet />
</template>
<h2>Contacts</h2>
<div class="contact-list">...</div>
<outlet />
```

Navigating from `/contacts/1` to `/contacts/2` preserves the contacts list - only the detail view at `<outlet />` changes.
Expand Down
36 changes: 16 additions & 20 deletions docs/guide/concepts/hydration.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,14 @@ The WebUI Framework plugin emits only these five comment markers. Text bindings,
Given this template:

```html
<template shadowrootmode="open">
<h1>{{title}}</h1>
<button @click="{toggle()}">Toggle</button>
<if condition="visible">
<p>Now you see me</p>
</if>
<for each="item in items">
<span data-id="{{item.id}}">{{item.name}}</span>
</for>
</template>
<h1>{{title}}</h1>
<button @click="{toggle()}">Toggle</button>
<if condition="visible">
<p>Now you see me</p>
</if>
<for each="item in items">
<span data-id="{{item.id}}">{{item.name}}</span>
</for>
```

The server renders something like:
Expand Down Expand Up @@ -192,16 +190,14 @@ The `webui:hydration-complete` event fires once after every component on the pag
Both plugins use the **same template syntax** - the difference is in the TypeScript component class, not the template:

```html
<template shadowrootmode="open">
<h1>{{title}}</h1>
<button @click="{onClick()}">Click me</button>
<for each="item in items">
<p>{{item.name}}</p>
</for>
<if condition="isVisible">
<span>Shown</span>
</if>
</template>
<h1>{{title}}</h1>
<button @click="{onClick()}">Click me</button>
<for each="item in items">
<p>{{item.name}}</p>
</for>
<if condition="isVisible">
<span>Shown</span>
</if>
```

Event binding, interpolation, conditionals, and loops are compiled identically regardless of the hydration plugin. For a complete syntax reference, see [Interactivity](/guide/concepts/interactivity).
Expand Down
28 changes: 10 additions & 18 deletions docs/guide/concepts/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ Only needed when your app has client-side navigation. Server-only apps with full

```html
<!-- app-shell.html -->
<template shadowrootmode="open">
<nav><a href="/">Home</a> <a href="/users">Users</a></nav>
<main><outlet /></main>
</template>
<nav><a href="/">Home</a> <a href="/users">Users</a></nav>
<main><outlet /></main>
```

**3. Start the router:**
Expand Down Expand Up @@ -63,11 +61,9 @@ Routes nest to any depth. Each parent component uses `<outlet />` where its chil

```html
<!-- section-page.html -->
<template shadowrootmode="open">
<h2>{{sectionName}}</h2>
<nav>topic links...</nav>
<outlet />
</template>
<h2>{{sectionName}}</h2>
<nav>topic links...</nav>
<outlet />
```

When navigating between child routes, **parent content is preserved**. Navigating from `/sections/1/topics/react` to `/sections/1/topics/css` only remounts the topic component - the section heading and nav stay.
Expand Down Expand Up @@ -339,19 +335,15 @@ Hidden routes use `style="display:none"` inline. If your CSS sets

```html
<!-- app-shell.html -->
<template shadowrootmode="open">
<header><nav-bar></nav-bar></header>
<main><outlet /></main>
</template>
<header><nav-bar></nav-bar></header>
<main><outlet /></main>
```

```html
<!-- contacts-page.html -->
<template shadowrootmode="open">
<h2>Contacts</h2>
<div class="list">...</div>
<outlet />
</template>
<h2>Contacts</h2>
<div class="list">...</div>
<outlet />
```

```typescript
Expand Down
20 changes: 9 additions & 11 deletions docs/tutorials/todo-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,17 +184,15 @@ Key points:
### Template – `src/todo-item/todo-item.html`

```html
<template shadowrootmode="open">
<div class="todo-item" @click="{onClick(e)}">
<button class="toggle" data-action="toggle" title="Toggle complete">
<if condition="state == 'done'">
<span class="check">&#10003;</span>
</if>
</button>
<span class="title">{{title}}</span>
<button class="delete" data-action="delete" title="Delete">&times;</button>
</div>
</template>
<div class="todo-item" @click="{onClick(e)}">
<button class="toggle" data-action="toggle" title="Toggle complete">
<if condition="state == 'done'">
<span class="check">&#10003;</span>
</if>
</button>
<span class="title">{{title}}</span>
<button class="delete" data-action="delete" title="Delete">&times;</button>
</div>
```

- **`<if condition="state == 'done'">`** – conditionally renders the checkmark
Expand Down
10 changes: 4 additions & 6 deletions examples/app/commerce/src/atoms/mp-price/mp-price.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<template shadowrootmode="open">
<span class="price">
<span class="amount">{{value}}</span>
<span class="currency">{{currencyCode}}</span>
</span>
</template>
<span class="price">
<span class="amount">{{value}}</span>
<span class="currency">{{currencyCode}}</span>
</span>
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<template shadowrootmode="open">
<div class="label">
<h3 class="title">{{title}}</h3>
<mp-price value="{{price}}" variant="pill" size="{{priceSize}}" currency-code="USD"></mp-price>
</div>
</template>
<div class="label">
<h3 class="title">{{title}}</h3>
<mp-price value="{{price}}" variant="pill" size="{{priceSize}}" currency-code="USD"></mp-price>
</div>
40 changes: 19 additions & 21 deletions examples/app/commerce/src/organisms/mp-carousel/mp-carousel.html
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
<template shadowrootmode="open">
<div class="carousel-wrapper">
<ul class="carousel">
<for each="product in products">
<li class="carousel-item">
<mp-product-card
handle="{{product.handle}}"
title="{{product.title}}"
price="{{product.price}}"
gradient="{{product.gradient}}"
image-url="{{product.imageUrl}}"
image-loading="lazy"
image-width="384"
image-height="384"
variant="carousel"
></mp-product-card>
</li>
</for>
</ul>
</div>
</template>
<div class="carousel-wrapper">
<ul class="carousel">
<for each="product in products">
<li class="carousel-item">
<mp-product-card
handle="{{product.handle}}"
title="{{product.title}}"
price="{{product.price}}"
gradient="{{product.gradient}}"
image-url="{{product.imageUrl}}"
image-loading="lazy"
image-width="384"
image-height="384"
variant="carousel"
></mp-product-card>
</li>
</for>
</ul>
</div>
Loading
Loading