Component shortcodes
On this page
OverviewYou can embed React, Vue, Svelte, and more into your existing templates. Let's learn how!
Prerequisites
Section titled "Prerequisites"First, install Preact + the Slinkity Preact renderer:
npm i -D preact @slinkity/preact
Then, add this renderer to a slinkity.config.js
at the base of your project:
// .eleventy.js or eleventy.config.js
const slinkity = require('slinkity')
const preact = require('@slinkity/preact')
module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(
slinkity.plugin,
slinkity.defineConfig({
renderers: [preact()],
})
)
}
First, install React's suite of dependencies + the Slinkity React renderer:
npm i -D react react-dom @slinkity/react
Then, add this renderer to a slinkity.config.js
at the base of your project:
// .eleventy.js or eleventy.config.js
const slinkity = require('slinkity')
const react = require('@slinkity/react')
module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(
slinkity.plugin,
slinkity.defineConfig({
renderers: [react()],
})
)
}
Slinkity is designed with Vue 3 in mind. Use Vue 2.x at your own risk!
First, install Vue 3 + the Slinkity Vue renderer:
npm i -D vue@3 @slinkity/vue
Then, add this renderer to a slinkity.config.js
at the base of your project:
// .eleventy.js or eleventy.config.js
const slinkity = require('slinkity')
const vue = require('@slinkity/vue')
module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(
slinkity.plugin,
slinkity.defineConfig({
renderers: [vue()],
})
)
}
First, install Svelte + the Slinkity Svelte renderer:
npm i -D svelte @slinkity/svelte
Then, add this renderer to a slinkity.config.js
at the base of your project:
// .eleventy.js or eleventy.config.js
const slinkity = require('slinkity')
const svelte = require('@slinkity/svelte')
module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(
slinkity.plugin,
slinkity.defineConfig({
renderers: [svelte()],
})
)
}
Basic usage
Section titled "Basic usage"Using the component
shortcode, you can insert components into any static template that 11ty supports.
Components must be placed in the _islands
directory relative to your input directory. You can override this from the Slinkity plugin config.
Say you've written a Vue component under _islands/Component.vue
. You can insert this component into your Nunjucks and Liquid templates like so:
<!--server-render only-->
{% island 'Component.vue' %}{% endisland %}
<!--server-render and hydrate client-side-->
{% island 'Component.vue', 'client:load' %}{% endisland %}
<!--render client-side only, no server rendering-->
{% clientOnlyIsland 'Component.vue' %}{% endclientOnlyIsland %}
These examples work from markdown (
.md
) and HTML (.html
) files as well. Each use Liquid syntax by default, though this can be overridden to Nunjucks using 11ty's template override configuration.
First, this will find and load _islands/Component.vue
. Note that the file extension is required (.jsx
, .tsx
, .svelte
, etc).
Also note that client-side JS is opt-in using a client:
directive. This allows you to use components for templating and only ship a JS bundle when the need arises.
💧 Learn more about partial hydration →
Pass props to shortcodes
Section titled "Pass props to shortcodes"You can also pass data to your components using a <!--slinkity-prop FSVZqx-->
shortcode.
Say you have a blog heading component written in your favorite framework (_includes/BlogHeading.jsx|vue|svelte
) that uses a title and 11ty's supplied date
object. You can pass these props like so, where 'date'
is the prop name and page.date
is the prop value:
{% island 'Date.jsx|vue|svelte' %}
{% prop 'date', page.date %}
{% prop 'title', 'My Slinktastic Blog' %}
{% endisland %}
You can access this prop inside your component like any other prop:
export default function BlogHeading({ title, date }) {
return (
<heading>
<h1>{title}</h1>
<p>Published on:<time datetime={date}>{date}</time></p>
</heading>
)
}
export default function BlogHeading({ title, date }) {
return (
<heading>
<h1>{title}</h1>
<p>Published on:<time datetime={date}>{date}</time></p>
</heading>
)
}
<template>
<heading>
<h1>{{ title }}</h1>
<p>Published on: <time :datetime="date">{{ date }}</time></p>
</heading>
</template>
<script>
export default {
props: ["date", "title"],
}
</script>
<script>
export let date = '';
export let title = '';
</script>
<heading>
<h1>{title}</h1>
<p>Published on:<time datetime={date}>{date}</time></p>
</heading>
Pass children / default slots to component
Section titled "Pass children / default slots to component"Any HTML inside your {% island %}
shortcode will be passed as children, or the default slot
when using Vue or Svelte.
Say you have a simple component to wrap text with a dropdown toggle:
export default function Dropdown({ heading, children }) {
return (
<details>
<summary>{heading}</summary>
{children}
</details>
)
}
export default function Dropdown({ heading, children }) {
return (
<details>
<summary>{heading}</summary>
{children}
</details>
)
}
<template>
<details>
<summary>{{ heading }}</summary>
<slot />
</details>
</template>
<script>
export default {
props: ["heading"],
};
</script>
<script>
export let heading = "";
</script>
<details>
<summary>{heading}</summary>
<slot />
</details>
You can pass children alongside your props like so:
{% island 'Dropdown.jsx|vue|svelte' %}
{% prop 'heading', 'Full disclosure' %}
<p>"details" and "summary" are kinda confusing element names</p>
{% endisland %}
Important gotcha: templating in children
Section titled "Important gotcha: templating in children"You may be rushing to try slotted components in your markdown:
{% island 'FancyBackground.jsx|vue|svelte' %}
### Why I love markdown
- Bulleted lists are easy
- Paragraph and code blocks are even easier
{% endisland %}
🚨 Careful, this won't work as written! Paired shortcode content is processed as plain HTML, so markdown syntax won't work as expected.
There is a solution though. Since you can still nest other shortcodes as paired shortcode content, you can use 11ty's handy renderTemplate
like so:
{% island 'FancyBackground.jsx|vue|svelte' %}
{% renderTemplate 'md' %}
### Why I love markdown
- Bulleted lists are easy
- Paragraph and code blocks are even easier
{% endrenderTemplate %}
{% endisland %}
Be sure to set up
renderTemplate
in your 11ty config before trying this. See their docs for more.
This will process your markdown, then pass the result to your component.
So injecting components into templates is nice... but what if we want to build the entire route using a component framework?