diff --git a/app/docs/md/conventions/browser.md b/app/docs/md/conventions/browser.md
index af64617d..e4414a1a 100644
--- a/app/docs/md/conventions/browser.md
+++ b/app/docs/md/conventions/browser.md
@@ -77,7 +77,7 @@ Write a pure function for returning the HTML markup for the `my-message.mjs` cus
```javascript
export default function MyMessage({ html, state }) {
- const { attrs=[] } = state
+ const { attrs={} } = state
const { message='' } = attrs
return html`
${ message }
`
@@ -117,12 +117,7 @@ class MyMessageElement extends HTMLElement {
}
html(strings, ...values) {
- const collect = []
- for (let i = 0; i < strings.length - 1; i++) {
- collect.push(strings[i], values[i])
- }
- collect.push(strings[strings.length - 1])
- return collect.join('')
+ return String.raw({ raw: strings }, ...values)
}
static get observedAttributes() {
diff --git a/app/docs/md/elements/state/context.md b/app/docs/md/elements/state/context.md
new file mode 100644
index 00000000..ed1d7150
--- /dev/null
+++ b/app/docs/md/elements/state/context.md
@@ -0,0 +1,77 @@
+---
+title: Context
+---
+
+The context object enables passing state to child elements without needing to resort to passing attributes down through multiple elements.
+
+## Set parent context
+
+The context object is passed as a key on the state object. Add data to the context object and it will be available to child elements.
+
+[Follow along by checking out the context demo from GitHub →](https://github.com/enhance-dev/context-demo)
+
+Given this markup you can use the context object to pass state directly to a deeply nested child element. Consider the page structure in the example below:
+
+
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+
+
+
+Add a heading key to the context object in the parent element:
+
+
+
+```javascript
+export default function ContextParent({ html, state }) {
+ const { context } = state
+ context.heading = 'Heading set via context'
+ return html`
+
+
+ `
+}
+```
+
+
+
+Render the heading passed via context in the deeply nested child element:
+
+
+```javascript
+export default function ContextHeading({ html, state }) {
+ const { context } = state
+ const { heading='Default heading' } = context
+ return html`
+
+
${heading}
+ `
+}
+```
+
+
+
+
diff --git a/app/docs/md/elements/state/index.md b/app/docs/md/elements/state/index.md
index dedcd464..2798fca2 100644
--- a/app/docs/md/elements/state/index.md
+++ b/app/docs/md/elements/state/index.md
@@ -38,12 +38,14 @@ export default function MyElement ({ html, state }) {
-The state object contains two top level entries:
+The state object contains four top level keys:
- `attrs`, which contains all the key value pairs of attributes passed into your custom element’s instance
- `store`, which contains the global state of your Enhance application
+- `instanceID`, which is a unique ID per instance of Custom Element
+- `context`, which is an Object that can be used to pass state to child elements to avoid prop drilling
-These two different entries allow you to work with both basic and complex state in powerful ways without the need for complex abstractions or third party libraries.
+These keys allow you to work with both basic and complex state in powerful ways without the need for complex abstractions or third party libraries.
diff --git a/app/docs/md/elements/state/instance-id.md b/app/docs/md/elements/state/instance-id.md
new file mode 100644
index 00000000..e7732fff
--- /dev/null
+++ b/app/docs/md/elements/state/instance-id.md
@@ -0,0 +1,23 @@
+---
+title: Instance ID
+---
+
+`instanceID` is a unique identifier that is generated per Custom Element instance. This enables you to differentiate between multiple instances of the same element on a page. It can also be useful when using a string based diffing library like [Morphdom](https://github.com/patrick-steele-idem/morphdom) which keys on unique identifiers to know when to update versus replace an element.
+
+```javascript
+export default function MyCard({ html, state }) {
+ const { attrs={}, instanceID='' } = state
+ const { content='', heading='' } = attrs
+
+ return html`
+
+ `
+}
+```
+
+
+ Pro tip: As in the example above, prefix the id with the element name in order to use the id with multiple child elements.
+
diff --git a/app/docs/nav-data.mjs b/app/docs/nav-data.mjs
index f1f4adf1..0524d959 100644
--- a/app/docs/nav-data.mjs
+++ b/app/docs/nav-data.mjs
@@ -82,7 +82,15 @@ export const data = [
path: '/docs/elements/state/',
label: 'State',
hasChildren: true,
- items: ['attributes', 'store'],
+ items: [
+ 'attributes',
+ 'store',
+ {
+ slug: 'instance-id',
+ label: 'Instance ID',
+ },
+ 'context',
+ ],
},
],
},
diff --git a/app/elements/docs/theme-toggle.mjs b/app/elements/docs/theme-toggle.mjs
index ecba35d8..99bea43e 100644
--- a/app/elements/docs/theme-toggle.mjs
+++ b/app/elements/docs/theme-toggle.mjs
@@ -43,8 +43,7 @@ export default function DocsThemeToggle({ html }) {