Asian Americans Advancing Justice — Stand Against Hatred
Eleventy
The possum is Eleventy’s mascot
Eleventy Documentation
WARNING:
This is an older version of Eleventy. Go to the newest Eleventy docs (current path: /docs/languages/webc/) or the full release history.
Menu
Eleventy 1.93s
Next.js 70.65s

WebC

Template Languages:

Logo for WebC

Contents

Type Value
Eleventy Name webc
File Extension *.webc
npm @11ty/webc and @11ty/eleventy-plugin-webc
GitHub 11ty/webc and 11ty/eleventy-plugin-webc

Why use WebC? Jump to heading

Performance Jump to heading

Compatible with Standards Jump to heading

Authoring Jump to heading

Resources Jump to heading

Installation Jump to heading

INFO:
Note that WebC support in Eleventy is not bundled with core! You must install the officially supported Eleventy plugin and the plugin requires Eleventy v2.0.0-beta.1 or newer.

It’s on npm at @11ty/eleventy-plugin-webc!

npm install @11ty/eleventy-plugin-webc

To add support for .webc files in Eleventy, add the plugin in your Eleventy configuration file:

Filename .eleventy.js
const pluginWebc = require("@11ty/eleventy-plugin-webc");

module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc);
};

You’re only allowed one module.exports in your configuration file. If you already have a configuration file, only copy the require and the addPlugin lines above!

Full options list (defaults shown)
const pluginWebc = require("@11ty/eleventy-plugin-webc");

module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc, {
// Glob to find no-import global components
// (The default changed from `false` in Eleventy WebC v0.7.0)
components: "_components/**/*.webc",

// Adds an Eleventy WebC transform to process all HTML output
useTransform: false,

// Additional global data used in the Eleventy WebC transform
transformData: {},
});
};

Syntax highlighting Jump to heading

Because WebC is HTML you can configure your editor to treat .webc files as
HTML, this should correctly syntax highlight your WebC files. Your editor of
choice should have some documentation on how to get this working.

Usage Jump to heading

There are a few different ways to use WebC in Eleventy:

Add a new .webc file Jump to heading

Adding the plugin will enable support for .webc files in your Eleventy project. Just make a new .webc HTML file in your Eleventy input directory and Eleventy will process it for you! Notably, .webc files will operate WebC in bundler mode, aggregating the CSS and JS in use on each individual page to create a bundle of the assets in use on the page.

WebC uses an HTML parser to process input files: use any HTML here!

Filename my-page.webc
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WebC Example</title>
</head>
<body>
WebC *is* HTML.
</body>
</html>

Non-traditional WebC usage Jump to heading

Use the Render plugin Jump to heading

Using Eleventy’s built-in Render plugin allows you to render WebC inside of an existing Liquid, Nunjucks, or 11ty.js template.

View this example in: Liquid Nunjucks 11ty.js Handlebars
Syntax Liquid
{% renderTemplate "webc" %}
<my-custom-component></my-custom-component>
{% endrenderTemplate %}
Syntax Nunjucks
{% renderTemplate "webc" %}
<my-custom-component></my-custom-component>
{% endrenderTemplate %}
Syntax JavaScript
module.exports = async function() {
let content = await this.renderTemplate(`<my-custom-component></my-custom-component>`, "webc");
return content;
};

The renderTemplate shortcode requires an async-friendly template language and is not available in Handlebars.

Pre-process HTML input as WebC Jump to heading

You can use the configuration option to change the default HTML preprocessor (from liquid) to webc. This might look like htmlTemplateEngine: "webc". Read more on the Eleventy documentation: Default Template Engine for HTML Files.

Post-process HTML output as WebC Jump to heading

This is a (last-resort?) catch-all option to let WebC process .html output files in your project (skipping any .webc input files to avoid double-processing templates). This feature makes use of Eleventy transforms and is most useful when you want to get up and running with WebC on an existing project quickly.

A few drawbacks to the transform method:

  1. This is the slowest build-performance method to implement WebC in a project, so try the other methods first!
  2. The WebC Eleventy transform operates with bundler mode disabled, which means that processes WebC but does not aggregate component JS or CSS. (Upvote this enhancement request)
The transform is disabled by default, you will need to use the useTransform option to enable it.
const pluginWebc = require("@11ty/eleventy-plugin-webc");

module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc, {
useTransform: true,
});
};

WebC Reference Jump to heading

Note that all webc: attributes are removed from the rendered output HTML.

HTML-only components Jump to heading

When a component has only content HTML (no CSS or JavaScript) it will ignore the host component tag in the output HTML. This enables HTML-only components to have zero overhead HTML. (You can opt-out of this behavior with webc:keep.)

Expand for Example
INFO:
WebC components are not limited to custom element name restrictions (e.g. my-component) here. You can use p, blockquote, h1, img, or any valid HTML tag name.
Filename page.webc
<!doctype html>
<title>WebC Example</title>
<my-component></my-component>
Filename components/my-component.webc
Components don’t need a root element, y’all.

Outputs:

Filename _site/page.html
<!doctype html>
<html>
<head>
<title>WebC Example</title>
</head>
<body>
Components don’t need a root element, y’all.
</body>
</html>

Asset bundling Jump to heading

For components that are not HTML-only (they do have CSS or JS), WebC will include the component tag in the output markup (e.g. <my-component>) (for styling or client scripting). (You can opt-out of this behavior with webc:nokeep.)

Expand for Example
INFO:
WebC components are not limited to custom element name restrictions (e.g. my-component) here. You can use p, blockquote, h1, img, or any valid HTML tag name.
Filename page.webc
<!doctype html>
<title>WebC Example</title>
<my-component></my-component>
Filename components/my-component.webc
Components don’t need a root element, y’all.
<style>/* Hi */</style>

Outputs:

Filename _site/page.html
<!doctype html>
<html>
<head>
<title>WebC Example</title>
</head>
<body>
<my-component>Components don’t need a root element, y’all.</my-component>
</body>
</html>

Eleventy runs WebC in Bundler mode. That means that when it finds <style>, <link rel="stylesheet">, or <script> elements in component definitions they are removed from the output markup and their content is aggregated together for re-use in asset bundles on the page. Read more about CSS and JS in WebC. (You can opt-out of this behavior with webc:keep.)

webc:keep Jump to heading

With an HTML-only component, you can use webc:keep on the host component to keep the tag around:

<html-only-component webc:keep></html-only-component>

You can also use webc:keep to opt-out of asset bundling for individual elements inside of a component definition:

<style webc:keep></style>
<script webc:keep></script>

You can also use webc:keep to save a <slot> for use in a client-side custom element.

webc:nokeep Jump to heading

With an CSS/JS component (not an HTML-only component), you can use webc:nokeep on the host component to drop the tag:

<css-js-component webc:nokeep></css-js-component>

webc:import Jump to heading

WebC will expand any component it finds using known components. You can also use webc:import to inline import a component definition. This import path is relative to the component file path. WebC checks for circular component dependencies and throws an error if one is encountered.

<any-tag-name webc:import="./components/my-component.webc"></any-tag-name>

Added in @11ty/webc@0.6.2You can import directly from an installed npm package. Eleventy will begin to supply WebC components with existing plugins. The Syntax Highlighter (4.2.0 or newer) supplies one that you can use today:

<syntax-highlight language="js" webc:import="npm:@11ty/eleventy-plugin-syntaxhighlight">
function myFunction() {
return true;
}
</syntax-highlight>

This uses the component tag name (syntax-highlight) to look for a WebC component at node_modules/@11ty/eleventy-plugin-syntaxhighlight/syntax-highlight.webc and imports it for use on this node. This works with a tag name override via webc:is too.

webc:if Jump to heading

Added in @11ty/webc@0.7.1

Use webc:if to conditionally render elements. Accepts arbitrary JavaScript (and is async-friendly). Similar to dynamic attributes, this also has access to component attributes and properties.

<div webc:if="true">This will render</div>
<div webc:if="false">This will not render</div>
<div webc:if="myAsyncHelper()">If the helper promise resolves to a truthy value, this will render</div>

You can use webc:type="js" (WebC v0.7.1+) to use JavaScript for more complex conditional logic (read more below).

webc:elseif and webc:else Jump to heading

Added in @11ty/webc@0.10.0

Adjacent siblings of webc:if can use webc:elseif="" and webc:else for additional conditional logic.

<div webc:if="false">This will not render</div>
<!-- interspersing comments works ok -->
<div webc:elseif="true">This will render</div>
<div webc:else>This will not render</div>

webc:for Loops Jump to heading

Added in @11ty/webc@0.10.0

Use webc:for to loop over data with HTML. It works with Objects and any Iterable (String, Array, Map, Set, etc).

The syntax should feel similar to JavaScript’s for statement.

Arrays (or any other Iterable) Jump to heading

<!-- renders three div elements -->
<div webc:for="item of [1, 2, 3]" @text="item"></div>

<!-- access the loop index (zero-indexed) -->
<div webc:for="(item, index) of [1, 2, 3]" @text="index"></div>

<!-- name these whatever you’d like -->
<div webc:for="myItem of [1, 2, 3]" @text="myItem"></div>
<div webc:for="(myItem, myIndex) of [1, 2, 3]" @text="myIndex"></div>

<!-- any iterable -->
<div webc:for="item of new Set([1, 2, 3])" @text="item"></div>

Objects Jump to heading

Note the use of in instead of of.

<!-- renders two div elements -->
<div webc:for="key in { a: 1, b: 2 }" @text="key"></div>

<!-- access the value -->
<div webc:for="(key, value) in { a: 1, b: 2 }" @text="value"></div>

<!-- access the loop index (zero-indexed) -->
<div webc:for="(key, value, index) in { a: 1, b: 2 }" @text="index"></div>

<!-- name these whatever you’d like -->
<div webc:for="(myKey, myValue, myIndex) in { a: 1, b: 2 }" @text="myIndex"></div>

<!-- use `Object.values` or `Object.keys`, sure -->
<div webc:for="value of Object.values({ a: 1, b: 2 })"></div>
<div webc:for="key of Object.keys({ a: 1, b: 2 })"></div>

Slots Jump to heading

Child content optionally precompiles using <slot> and [slot] too. This example is using an HTML-only component.

Filename page.webc
<my-component></my-component>
<my-component>This is the default slot</my-component>
Filename components/my-component.webc
<p><slot>Fallback slot content</slot></p>

Compiles to:

<p>Fallback slot content</p>
<p>This is the default slot</p>

If your WebC component wants to output a <slot> tag in the compiled markup (for use in client JavaScript), use the webc:keep attribute (e.g. <slot webc:keep>).

INFO:
Per web component standard conventions, if your component file contains no content markup (e.g. empty or only <style>/<script>), <slot></slot> is implied and the default slot content will be included automatically. If the WebC component file does contain content markup, the content passed in as the default slot requires <slot> to be included.

Named slots Jump to heading

This works with named slots (e.g. <span slot="named-slot">) too.

Expand for Example
Filename page.webc
<my-component>
This is the default slot.
<strong slot="named-slot">This is a named slot</strong>
This is also the default slot.
</my-component>
Filename components/my-component.webc
<p><slot name="named-slot"></slot></p>

Compiles to:

<p><strong>This is a named slot.</strong></p>

Attributes and webc:root Jump to heading

Filename page.webc
<my-component class="sr-only"></my-component>

Inside of your component definition, you can add attributes to the outer host component using webc:root:

Filename components/my-component.webc
<template webc:root class="another-class">
Some component content
</template>

class and style attribute values are merged as expected between the host component and the webc:root element.

Override the host component tag Jump to heading

You can use webc:root="override" together to override the host component tag name! This isn’t very useful for HTML-only components (which leave out the host component tag) but is very useful when your component has style/scripts.

Filename components/my-component.webc
<button webc:root="override">Some component content</button>
<style>/* Hi */</style>

Nesting Jump to heading

It’s worth noting also that webc:root can be nested inside of other content—it does not need to exist at the top level of the component definition (framework folks love nested things deeply in div right).

Filename components/my-component.webc
<div>
<div>
<template webc:root="override" class="another-class">
Some component content
</template>
</div>
</div>

Props (Properties) Jump to heading

Make any attribute into a prop by prefixing it with @. Props are “private” attributes that don’t end up in the output HTML (they are private to WebC). They are identical to attributes except that they are filtered from the output HTML.

Filename page.webc
<my-component @prop="Hello"></my-component>
Filename components/my-component.webc
<p @text="prop"></p>
<!-- outputs <p>Hello</p> -->

Dynamic attributes and properties Jump to heading

Make any attribute or property dynamic (using JavaScript for the value instead of a string) by prefixing it with a colon (:). You have access to host component attributes, props, and page data here!

Filename page.webc
<avatar-image src="my-image.jpeg" alt="Zach is documenting this project" :@dynamic-prop="'hello'"></avatar-image>
Filename components/avatar-image.webc
<img :src="src" :alt="alt" class="avatar-image">

@attributes Jump to heading

Added in @11ty/webc@0.9.0You can use @attributes to render all of the attributes (including on host component) to the current node.

Filename components/avatar-image.webc
<!-- will render all attributes including `src` and `alt` from the host component -->
<img @attributes class="avatar-image">

You can use this to render an arbitrary object as attributes too (note the parentheses to avoid JavaScript parsing as a block + label):

<img @attributes="({ myattribute: 'myValue'})">

@html Jump to heading

We surface a special @html prop to override any tag content with custom JavaScript.

<template @html="'Template HTML'"></template>
<template @html="dataProperty"></template>
<!-- webc:nokeep will replace the outer element -->
<template @html="'Template HTML'" webc:nokeep></template>
<!-- No reprocessing as WebC (useful in Eleventy layouts) -->
<!-- Where `myHtmlContent` is a variable holding an arbitrary HTML string -->
<template @raw="myHtmlContent" webc:nokeep></template>

@raw Jump to heading

Added in @11ty/webc@0.7.1

As noted in @html, you can use @raw as an alias for webc:raw @html.

@text Jump to heading

Added in @11ty/webc@0.6.0

We provide a special @text prop to override any tag content with custom JavaScript. The entire value returned here will be escaped!

<p @text="dataProperty"></p>

<!-- When dataProperty contains `<p>This is text</p>`, this renders: -->
<p>&lt;p&gt;This is text&lt;/p&gt;</p>
<!-- webc:nokeep will replace the outer element -->
<p @text="dataProperty" webc:nokeep></p>

webc:is Jump to heading

Remap a component to another component name.

<div webc:is="my-component"></div>

<!-- equivalent to -->
<my-component></my-component>

webc:scoped Jump to heading

We include a lightweight mechanism (webc:scoped) to scope component CSS. Selectors are prefixed with a new component class name. The class name is based on a hash of the style content (for fancy de-duplication of identical component styles).

Expand for example
Filename page.webc
<my-component>Default slot</my-component>

If you use :host it will be replaced with that class selector.

Filename components/my-component.webc
<style webc:scoped>
:host {
color: blue;
}
:host:defined {
color: rebeccapurple;
}
</style>

This outputs:

<my-component class="wcl2xedjk">Default slot</my-component>

and aggregates the following CSS to the bundle:

.wcl2xedjk{color:blue}
.wcl2xedjk:defined{color:rebeccapurple}
INFO:
CSS bundling opinion alert: Some folks recommend using Declarative Shadow DOM for component style encapsulation. This is a great method! It has 2 major drawbacks:

1. The progressive enhancement story requires ubiquitous browser support before using it for content in the critical rendering path.
2. It requires <style> duplication in each instance of the component.

Just be aware of these tradeoffs and note that you can use both methods in WebC!

webc:scoped="my-prefix" Jump to heading

You can also specify an attribute value to webc:scoped to hard code your own component prefix (e.g. <style webc:scoped="my-prefix">). This allows the CSS to look a bit more friendly and readable. We will automatically check for duplicate values in your component tree and throw an error if collisions occur.

Using JavaScript to Setup your Component Jump to heading

Added in @11ty/webc@0.9.0You can now also use <script webc:setup> to run arbitrary JavaScript and provide data and markup to your component. Any top level variables declared here are available in your component as local data.

This is similar to using JavaScript as a custom Eleventy Front Matter type although data in webc:setup is scoped to the component and does not flow back up in the Data Cascade.

Filename components/my-component.webc
<script webc:setup>
const myHtml = "<my-webc-component></my-webc-component>";

function alwaysBlue() {
return "blue";
}
</script>

<div @html="myHtml"></div>
<div @raw="myHtml"></div><!-- @raw does not reprocess as WebC -->
<div @html="alwaysBlue()"></div>

Works with var, let, const, function, Array and Object destructuring assignment.

Using Template Syntax to Generate Content Jump to heading

The Custom Transforms feature (e.g. webc:type) in the Eleventy WebC plugin has been wired up to the Eleventy Render plugin to allow you to use existing Eleventy template syntax inside of WebC.

INFO:
Note that the webc:type="11ty" feature is exclusive to the Eleventy WebC plugin and is not available in non-Eleventy independent WebC.

Use webc:type="11ty" with the 11ty:type attribute to specify a valid template syntax.

Filename my-page.webc
---
frontmatterdata: "Hello from Front Matter"
---
<template webc:type="11ty" 11ty:type="liquid,md">
{% assign t = "Liquid in WebC" %}
## {{ t }}

_{{ frontmatterdata }}_
</template>

Using JavaScript to Generate Content Jump to heading

You can also transform individual element content using webc:type. In addition to webc:type="11ty", there are three more bundled types:

  1. webc:type="js" Added in @11ty/webc@0.7.1
  2. webc:type="render" (superceded by webc:type="js")
  3. webc:type="css:scoped" (internal for webc:scoped—but overridable!)

JavaScript Render Functions: webc:type="js" and webc:type="render" Jump to heading

Added in @11ty/webc@0.7.1 Run any arbitrary server JavaScript in WebC. Outputs the result of the very last statement executed in the script. Async-friendly (return a promise and we’ll resolve it).

Filename page.webc
<img src="my-image.jpeg" alt="An excited Zach is trying to finish this documentation">
Filename components/img.webc
<script webc:type="js" webc:root>
if(!alt) {
throw new Error("oh no you didn’t");
}
`<img src="${src}" alt="${alt}">`;
</script>
Expand to see this example with webc:type="render"
<script webc:type="render">
function() {
if(!this.alt) {
throw new Error("oh no you didn’t");
}
// Free idea: use the Eleventy Image plugin to return optimized markup
return `<img src="${this.src}" alt="${this.alt}">`;
}
</script>

Or use a JavaScript render function to generate some CSS:

Filename page.webc
<style webc:is="add-banner-to-css" @license="MIT licensed">
p { color: rebeccapurple; }
</style>
Filename components/add-banner-to-css.webc
<template webc:is="style" webc:root="override">
<script webc:type="js">`/* ${license} */`</script>
<slot></slot>
</template>
Expand to see this example with webc:type="render"
<template webc:is="style" webc:root="override">
<script webc:type="render">
function() {
return `/* ${this.license} */`;
}
</script>
<slot></slot>
</template>
Expand to see another example of a more complex conditional using webc:type="js"

Note that you can also use webc:if!

<script webc:type="js">
if(alt) {
`<img src="${src}" alt="${alt}">`
} else {
`<a href="${src}">Your image didn’t have an alt so you get this link instead.</a>`
}
</script>

Bonus tips:

Extra data for JavaScript Render Functions Jump to heading

Added in @11ty/webc@0.9.0

Read more at Issue #104.

Expand to see an img component example

One might imagine an <img> component definition that merges and re-uses all host component attributes correctly like this:

Filename components/img.webc
<script webc:type="js" webc:root="override">
`<img ${webc.renderAttributes(webc.attributes)}>`
</script>

webc:raw Jump to heading

Use webc:raw to opt-out of WebC template processing for all child content of the current node. Notably, attributes on the current node will be processed. This works well with <template>!

Filename components/my-component.webc
<template webc:raw>
Leave me out of this.
<style>
p { color: rebeccapurple; }
</style>
</template>

webc:ignore Jump to heading

Added in @11ty/webc@0.9.0Use webc:ignore to completely ignore a node and not process or output anything to do with it. Useful for server-side comments or documentation on a component.

Filename components/my-component.webc
<template webc:ignore>
Here’s how you might use this component:

<my-component>Nothing in here will be processed</my-component>
</template>

Server-only comments Jump to heading

Added in @11ty/webc@0.10.0

Instead of an HTML comment that will show up in rendered output, you can add one or more dashes to the beginning/end to tell WebC to strip this from the output. Great for server-side comments.

Filename components/my-component.webc
<!--- WebC will remove this --->
<!-- This will *not* be removed and is rendered to the output -->
<!------- WebC will remove this, too ------->

Custom Transforms Jump to heading

This plugin provides a few transforms out of the box: webc:type="js", webc:type="render", webc:type="css:scoped", and webc:type="11ty".

However, adding your own webc:type Custom Transform directly to WebC is not yet available in the Eleventy WebC plugin! If this is something folks would like to see added, please let us know!

Do note that you can add your own custom template engine which would be available via webc:type="11ty" (e.g. <style webc:type="11ty" 11ty:type="sass">).

Helper Functions Jump to heading

WebC Helpers are JavaScript functions available in dynamic attributes, @html, @raw, and render functions.

Eleventy-provided Helpers Jump to heading

Added in @11ty/eleventy-plugin-webc@0.5.0Included with Eleventy WebC, JavaScript template functions and Universal Filters are provided automatically as WebC Helpers.

This includes url, slugify, log and others!

<!-- Use the  Eleventy provided `url` universal filter -->
<a :href="url('/local-path/')">My Link</a>

Supply your own Helper Jump to heading

Filename .eleventy.js
module.exports = function(eleventyConfig) {
// via Universal Filter
eleventyConfig.addFilter("alwaysRed", () => "Red");

// or via JavaScript Template Function directly
eleventyConfig.addJavaScriptFunction("alwaysBlue", () => "Blue");

// Don’t forget to add the WebC plugin in your config file too!
};
<div @html="alwaysRed()"></div>
<div @html="alwaysBlue()"></div>

<!-- renders as: -->
<div>Red</div>
<div>Blue</div>

Subtleties and Limitations Jump to heading

Void elements Jump to heading

Custom elements (per specification) are not supported as void elements: they require both a starting and ending tag.

Practically speaking, this means a WebC component can not be self-closing. You can workaround this limitation using webc:is (e.g. <img webc:is="my-component">).

<head> Components Jump to heading

There are a few wrinkles when using an HTML parser with custom elements. Notably, the parser tries to force custom element children in the <head> over to the <body>. To workaround this limitation, use webc:is.

Expand for a few example workarounds
<head webc:is="my-custom-head">
<!-- this is slot content, yes you can use named slots here too -->
</head>
<head>
<!-- <my-custom-head> is not allowed here but
<meta webc:is="my-custom-head> is -->

<meta webc:is="my-custom-head">
<title webc:is="my-custom-title">Default Title</title>
</head>

Rendering Modes Jump to heading

There are two different rendering modes in Eleventy: page and component. We attempt to guess the rendering mode that you’d like based on the markup you supply. The page rendering mode is for rendering full HTML pages. The component rendering mode is for fragments of HTML. Most of the time you won’t need to worry about this distinction but it is included in the documentation for completeness.

Differences from HTML parsing Jump to heading

Added in @11ty/webc@0.9.0WebC processes content inside of both <template> and <noscript> tags. The HTML parser treats these as plaintext.

Eleventy + WebC Features Jump to heading

Front Matter Jump to heading

WebC in Eleventy works automatically with standard Eleventy conventions for front matter (though front matter in Eleventy is optional).

Filename with-front-matter.webc
---
layout: "my-layout.webc"
---
WebC *is* HTML.
Expand to see an example my-layout.webc

The above example assumes the existence of _includes/my-layout.webc (an Eleventy layout).

Filename _includes/my-layout.webc
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WebC Example</title>
</head>
<body @raw="content"></body>
</html>

Notable note: front matter (per standard Eleventy conventions) is supported in page-level templates only (.webc files in your input directory) and not in components (see below).

Defining Components Jump to heading

Components are the magic of WebC and there are a few ways to define components in WebC:

  1. Use global no-import components specified in your config file.
  2. Specify a glob of no-import components at a directory or template level in the data cascade.
  3. You can use webc:import inside of your components to import another component directly.
INFO:
Notably, WebC components can have any valid HTML tag name and are not restricted to the same naming limitations as custom elements (they do not require a dash in the name).

Global no-import Components Jump to heading

Use the components property in the options passed to addPlugin in your Eleventy configuration file to specify project-wide WebC component files available for use in any page.

We accept:

Filename .eleventy.js
const pluginWebc = require("@11ty/eleventy-plugin-webc");

module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(pluginWebc, {
// Glob to find no-import global components
// This path is relative to the project-root!
// The default value is shown:
components: "_components/**/*.webc",

// or an Array (Eleventy WebC v0.9.2+)
components: [
"_components/**/*.webc",
"npm:@11ty/is-land/*.webc"
"npm:@11ty/eleventy-plugin-syntaxhighlight/*.webc"
]
});
};

Notably, the path for components is relative to your project root (not your project’s input directory).

The file names of components found in the glob determine the global tag name used in your project (e.g. _components/my-component.webc will give you access to <my-component>).

Declaring Components in Front Matter Jump to heading

You can also use and configure specific components in front matter (or, via any part of the data cascade—scoped to a folder or a template) by assigning a glob (or array of globs) to the property at webc.components:

Filename my-directory/my-page.webc
---
layout: "my-layout.webc"
webc:
components: "./webc/*.webc"
---
<my-webc-component>WebC *is* HTML.</my-webc-component>
WARNING:

By default these paths are relative to the template file. If you’re setting this in the data cascade in a directory data file that will apply multiple child folders deep, it might be better to:

  1. Use the global no-import components option.
  2. Use ~/ as a prefix (e.g. ~/my-directory/webc/*.webc) to alias to the project’s root directory.

CSS and JS (Bundler mode) Jump to heading

Eleventy WebC will bundle any specific page’s assets (CSS and JS used by components on the page). These are automatically rolled up when a component uses <script>, <script src>, <style>, or <link rel="stylesheet">. You can use this to implement component-driven Critical CSS.

INFO:
Note on Declarative Shadow DOM: elements inside of declarative shadow root template (<template shadowrootmode> or the deprecated <template shadowroot>) are left as is and not bundled.
Filename _components/my-webc-component.webc
<style>/* This is component CSS */</style>
<script>/* This is component JS */</script>

<!-- Local file references work too -->
<link rel="stylesheet" href="my-file.css">
<script src="my-file.js"></script>

As shown above this also includes <link rel="stylesheet"> and <script src> when the URLs point to files on the file system (remote URL sources are not yet supported).

You can opt-out of bundling on a per-element basis using webc:keep.

Filename _includes/layout.webc
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WebC Example</title>

<!-- inline bundles -->
<style @raw="getBundle('css')" webc:keep></style>
<script @raw="getBundle('js')" webc:keep></script>

<!-- or write your bundle to a file -->
<link rel="stylesheet" :href="getBundleFileUrl('css')">
<script :src="getBundleFileUrl('js')"></script>
</head>
<body @raw="content"></body>
</html>

Bundle Code Ordering Jump to heading

The order of the code in these bundles is determined by the dependency order of the components, from most specific to least specific!

Expand to see an example

Say we have an index.webc page that uses a header.webc component.

Filename index.webc
<style>/* index.webc */</style>
<header></header>
Filename _components/header.webc
<style>/* header.webc */</style>

The CSS bundle will look like:

/* header.webc */
/* index.webc */

Access Bundles in other Template Engines Jump to heading

You can access these bundles in other templates types too (.njk, .liquid, etc.).

Added in @11ty/eleventy-plugin-webc@0.9.0Eleventy WebC uses eleventy-plugin-bundle behind the scenes to implement bundling. This plugin provides getBundle and getBundleFileUrl universal shortcodes for use in any template type (including WebC as shown above).

WebC v0.8.0 and older: Check out the deprecated (but still in place for backwards compatibility) webcGetCss and webcGetJs universal filters for bundle output.
Filename _includes/layout.njk
<style>{{ page.url | webcGetCss | safe }}</style>
<script>{{ page.url | webcGetJs | safe }}</script>
<!-- write to a file -->
<link rel="stylesheet" href="{% getBundleFileUrl "css" %}">
Filename _includes/layout.liquid
<style>{{ page.url | webcGetCss }}</style>
<script>{{ page.url | webcGetJs }}</script>

Asset bucketing Jump to heading

There is an additional layer of bundling here that you can use that we call Bucketing. Components can use webc:bucket to output to any arbitrary bucket name.

In this component, we have component code that outputs to two separate buckets:

Filename _components/my-webc-component.webc
<style>/* This CSS is put into the default bucket */</style>
<script>/* This JS is put into the default bucket */</script>
<style webc:bucket="defer">/* This CSS is put into the `defer` bucket */</style>
<script webc:bucket="defer">/* This JS is put into the `defer` bucket */</script>

When <my-webc-component> is used on a page, it will roll the assets to the page-specific bucket bundles for CSS and JavaScript.

Then you can output those bucket bundles anywhere on your page like this (here we’re using an Eleventy layout file):

Filename _includes/layout.webc
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WebC Example</title>
<!-- Default bucket -->
<style @raw="getBundle('css')" webc:keep></style>
<script @raw="getBundle('js')" webc:keep></script>
</head>
<body>
<template @raw="content" webc:nokeep></template>

<!-- `defer` bucket -->
<style @raw="getBundle('css', 'defer')" webc:keep></style>
<script @raw="getBundle('js', 'defer')" webc:keep></script>
</body>
</html>

Cascading Asset Buckets Jump to heading

Added in @11ty/webc@0.9.1 Additionally webc:bucket can be added to any tag and will cascade to all child content.

Consider this WebC page:

Filename index.webc
<!-- has an implied webc:bucket="default" -->
<my-component></my-component>

<div webc:bucket="defer">
<!-- each of these have webc:bucket="defer" -->
<!-- (including any nested components inside, too) -->
<footnote-references></footnote-references>

<my-footer></my-footer>
</div>

Setting webc:bucket now cascades to all of the children as if they had webc:bucket="defer" assigned to each of them individually. All assets used in those components will now be rolled up into the defer bucket.

Conflicts and hoisting

What happens when a component is used in multiple distinct buckets?

Filename index.webc
<!-- has an implied webc:bucket="default" -->
<my-component></my-component>

<div webc:bucket="defer">
<my-component></my-component>
</div>

When duplicates and conflicts occur, WebC will hoist the component code to find the nearest shared bucket for you. In the above example, the CSS and JS for <my-component> will be loaded in the default bucket and only in the default bucket.

Use with is-land Jump to heading

You can also use this out of the box with Eleventy’s is-land component for web component hydration.

At the component level, components can declare their own is-land loading conditions.

Filename index.webc
<is-land on:visible webc:import="npm:@11ty/is-land">
<template data-island>
<!-- CSS -->
<style webc:keep>
/* This CSS applies on:visible */
</style>
<link rel="stylesheet" href="arbitrary.css" webc:keep>

<!-- JS -->
<script type="module" webc:keep>
console.log("This JavaScript runs on:visible");
</script>
<script type="module" src="arbitrary.js" webc:keep></script>
</template>
</is-land>

Other pages in Template Languages: