diff --git a/.changeset/pink-toes-shake.md b/.changeset/pink-toes-shake.md
new file mode 100644
index 000000000..16ab79a5e
--- /dev/null
+++ b/.changeset/pink-toes-shake.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Expose slots to components
diff --git a/docs/reference/api-reference.md b/docs/reference/api-reference.md
index 3f3d8526b..e997a1859 100644
--- a/docs/reference/api-reference.md
+++ b/docs/reference/api-reference.md
@@ -49,6 +49,17 @@ const data = Astro.fetchContent('../pages/post/*.md'); // returns an array of po
}[]
```
+### `Astro.slots`
+
+`Astro.slots` returns an object with any slotted regions passed into the current Astro file.
+
+```js
+const {
+ heading as headingSlot, // true or undefined, based on whether `<* slot="heading">` was used.
+ default as defaultSlot, // true or undefined, based on whether `<* slot>` or `<* default>` was used.
+} = Astro.slots;
+```
+
### `Astro.request`
`Astro.request` returns an object with the following properties:
diff --git a/docs/src/pages/reference/api-reference.md b/docs/src/pages/reference/api-reference.md
index 624ed2986..08178b4b5 100644
--- a/docs/src/pages/reference/api-reference.md
+++ b/docs/src/pages/reference/api-reference.md
@@ -86,6 +86,17 @@ const path = Astro.site.pathname;
Welcome to {path}
```
+### `Astro.slots`
+
+`Astro.slots` returns an object with any slotted regions passed into the current Astro file.
+
+```js
+const {
+ heading as headingSlot, // true or undefined, based on whether `<* slot="heading">` was used.
+ default as defaultSlot, // true or undefined, based on whether `<* slot>` or `<* default>` was used.
+} = Astro.slots;
+```
+
## `getStaticPaths()`
If a page uses dynamic params in the filename, that component will need to export a `getStaticPaths()` function.
diff --git a/packages/astro/src/compiler/index.ts b/packages/astro/src/compiler/index.ts
index 7f416a30a..62809b285 100644
--- a/packages/astro/src/compiler/index.ts
+++ b/packages/astro/src/compiler/index.ts
@@ -158,12 +158,25 @@ import { __astro_hoisted_scripts } from 'astro/dist/internal/__astro_hoisted_scr
const __astroScripts = __astro_hoisted_scripts([${result.components.map((n) => `typeof ${n} !== 'undefined' && ${n}`)}], ${JSON.stringify(result.hoistedScripts)});
const __astroInternal = Symbol('astro.internal');
const __astroContext = Symbol.for('astro.context');
+const __astroSlotted = Symbol.for('astro.slotted');
async function __render(props, ...children) {
const Astro = Object.create(__TopLevelAstro, {
props: {
value: props,
enumerable: true
},
+ slots: {
+ value: children.reduce(
+ (slots, child) => {
+ for (let name in child.$slots) {
+ slots[name] = Boolean(child.$slots[name])
+ }
+ return slots
+ },
+ {}
+ ),
+ enumerable: true
+ },
pageCSS: {
value: (props[__astroContext] && props[__astroContext].pageCSS) || [],
enumerable: true
diff --git a/packages/astro/test/astro-slots.test.js b/packages/astro/test/astro-slots.test.js
index 72b53c3e6..354036873 100644
--- a/packages/astro/test/astro-slots.test.js
+++ b/packages/astro/test/astro-slots.test.js
@@ -74,4 +74,60 @@ Slots('Slots work on Components', async ({ runtime }) => {
assert.equal($('#default').children('astro-component').length, 1, 'Slotted component into default slot');
});
+Slots('Slots API work on Components', async ({ runtime }) => {
+ // IDs will exist whether the slots are filled or not
+ {
+ const result = await runtime.load('/slottedapi-default');
+ assert.ok(!result.error, `build error: ${result.error}`);
+
+ const $ = doc(result.contents);
+
+ assert.equal($('#a').length, 1);
+ assert.equal($('#b').length, 1);
+ assert.equal($('#c').length, 1);
+ assert.equal($('#default').length, 1);
+ }
+
+ // IDs will not exist because the slots are not filled
+ {
+ const result = await runtime.load('/slottedapi-empty');
+ assert.ok(!result.error, `build error: ${result.error}`);
+
+ const $ = doc(result.contents);
+
+ assert.equal($('#a').length, 0);
+ assert.equal($('#b').length, 0);
+ assert.equal($('#c').length, 0);
+ assert.equal($('#default').length, 0);
+ }
+
+ // IDs will exist because the slots are filled
+ {
+ const result = await runtime.load('/slottedapi-filled');
+ assert.ok(!result.error, `build error: ${result.error}`);
+
+ const $ = doc(result.contents);
+
+ assert.equal($('#a').length, 1);
+ assert.equal($('#b').length, 1);
+ assert.equal($('#c').length, 1);
+
+ assert.equal($('#default').length, 0); // the default slot is not filled
+ }
+
+ // Default ID will exist because the default slot is filled
+ {
+ const result = await runtime.load('/slottedapi-default-filled');
+ assert.ok(!result.error, `build error: ${result.error}`);
+
+ const $ = doc(result.contents);
+
+ assert.equal($('#a').length, 0);
+ assert.equal($('#b').length, 0);
+ assert.equal($('#c').length, 0);
+
+ assert.equal($('#default').length, 1); // the default slot is filled
+ }
+});
+
Slots.run();
diff --git a/packages/astro/test/fixtures/astro-slots/src/components/SlottedAPI.astro b/packages/astro/test/fixtures/astro-slots/src/components/SlottedAPI.astro
new file mode 100644
index 000000000..e1b00fff8
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-slots/src/components/SlottedAPI.astro
@@ -0,0 +1,15 @@
+{Astro.slots.a &&
+
+
}
+
+{Astro.slots.b &&
+
+
}
+
+{Astro.slots.c &&
+
+
}
+
+{Astro.slots.default &&
+
+
}
diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default-filled.astro b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default-filled.astro
new file mode 100644
index 000000000..2800cb94d
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default-filled.astro
@@ -0,0 +1,15 @@
+---
+import Slotted from '../components/SlottedAPI.astro';
+---
+
+
+
+
+
+
+
+
+ Default
+
+
+
diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default.astro b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default.astro
new file mode 100644
index 000000000..349d63683
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-default.astro
@@ -0,0 +1,13 @@
+---
+import Slotted from '../components/Slotted.astro';
+---
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-empty.astro b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-empty.astro
new file mode 100644
index 000000000..2f2ad04e9
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-empty.astro
@@ -0,0 +1,13 @@
+---
+import Slotted from '../components/SlottedAPI.astro';
+---
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-filled.astro b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-filled.astro
new file mode 100644
index 000000000..01714e5d1
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-filled.astro
@@ -0,0 +1,17 @@
+---
+import Slotted from '../components/SlottedAPI.astro';
+---
+
+
+
+
+
+
+
+
+ A
+ B
+ C
+
+
+