diff --git a/doc/component.md b/doc/component.md
index 4905e206..0c4acdaf 100644
--- a/doc/component.md
+++ b/doc/component.md
@@ -928,6 +928,21 @@ is not allowed. A workaround could be to wrap the content in a div:
```
+Default slot: the first element inside the widget which is not a named slot will
+be considered the `default` slot. For example:
+
+```xml
+
+
+ some content
+
+
+
+
+
+
+```
+
### Asynchronous Rendering
Working with asynchronous code always adds a lot of complexity to a system. Whenever
diff --git a/src/qweb_extensions.ts b/src/qweb_extensions.ts
index cdc7b737..28034076 100644
--- a/src/qweb_extensions.ts
+++ b/src/qweb_extensions.ts
@@ -508,7 +508,11 @@ QWeb.addDirective({
ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`);
if (async) {
ctx.addLine(`const patchQueue${widgetID} = [];`);
- ctx.addLine(`c${ctx.parentNode}.push(w${widgetID} && w${widgetID}.__owl__.pvnode || null);`);
+ ctx.addLine(
+ `c${
+ ctx.parentNode
+ }.push(w${widgetID} && w${widgetID}.__owl__.pvnode || null);`
+ );
} else {
ctx.addLine(`c${ctx.parentNode}.push(null);`);
}
@@ -543,17 +547,26 @@ QWeb.addDirective({
);
// SLOTS
- const slotNodes = node.querySelectorAll("[t-set]");
- if (slotNodes.length) {
+ if (node.childElementCount) {
+ const clone = node.cloneNode(true);
+ const slotNodes = clone.querySelectorAll("[t-set]");
const slotId = qweb.nextSlotId++;
- for (let i = 0, length = slotNodes.length; i < length; i++) {
- const slotNode = slotNodes[i];
- const key = slotNode.getAttribute("t-set")!;
- slotNode.removeAttribute("t-set");
- const slotFn = qweb._compile(`slot_${key}_template`, slotNode);
- qweb.slots[`${slotId}_${key}`] = slotFn.bind(qweb);
- }
ctx.addLine(`w${widgetID}.__owl__.slotId = ${slotId};`);
+ if (slotNodes.length) {
+ for (let i = 0, length = slotNodes.length; i < length; i++) {
+ const slotNode = slotNodes[i];
+ slotNode.parentElement!.removeChild(slotNode);
+ const key = slotNode.getAttribute("t-set")!;
+ slotNode.removeAttribute("t-set");
+ const slotFn = qweb._compile(`slot_${key}_template`, slotNode);
+ qweb.slots[`${slotId}_${key}`] = slotFn.bind(qweb);
+ }
+ }
+ if (clone.childElementCount) {
+ const content = clone.children[0];
+ const slotFn = qweb._compile(`slot_default_template`, content);
+ qweb.slots[`${slotId}_default`] = slotFn.bind(qweb);
+ }
}
ctx.addLine(`def${defID} = w${widgetID}._prepare();`);
diff --git a/tests/component.test.ts b/tests/component.test.ts
index 57efd19d..e85adb9a 100644
--- a/tests/component.test.ts
+++ b/tests/component.test.ts
@@ -3148,4 +3148,27 @@ describe("t-model directive", () => {
expect(comp.state.number).toBe("invalid");
expect(fixture.innerHTML).toBe("invalid
");
});
+
+ test("content is the default slot", async () => {
+ env.qweb.addTemplates(`
+
+
+
+ sts rocks
+
+
+
+
+ `);
+ class Dialog extends Widget {}
+ class Parent extends Widget {
+ widgets = { Dialog };
+ }
+ const parent = new Parent(env);
+ await parent.mount(fixture);
+
+ expect(fixture.innerHTML).toBe(
+ ""
+ );
+ });
});