WebC
Single File Web Components
README
WebC is for Single File Web Components
Features
Framework-independent standalone HTML serializer for generating markup for Web Components.
Expand any HTML element (including custom elements and web components) to HTML with defined conventions from web standards.
This means that Web Components created with WebC are compatible with server-side rendering (without duplicating author-written markup).
Compilation tools to aggregate component-level assets (CSS or JS) for critical CSS or client JavaScript.
Opt-in to scope your component CSS using WebC’s built-in CSS prefixer.
Or, use browser-native Shadow DOM style scoping (for future-compatibility when Declarative Shadow DOM browser support is ubiquitous)
Progressive-enhancement friendly.
Streaming friendly.
Shadow DOM friendly.
Async friendly.
The .webc file extension is recommended (not a requirement)—you _can_ use .html.
Tip for Visual Studio Code users: go to Preferences -> Settings -> Files: Associations to add a mapping for *.webc to html.
Integrations/Plugins
[@11ty/eleventy-plugin-webc](https://www.11ty.dev/docs/languages/webc/) adds WebC to Eleventy
Testimonials
“javascript frameworks are dead to me”—Andy Bell
“The DX and authoring model you landed on here looks fantastic”—Addy Osmani
“Really like the programmatic API approach over using a bundler to pre-compile and then serve.”—Harminder Virk
Similar Works
Folks doing similar things with Web Components: check them out!
Installation
Note: if you’re not building a plugin or integration for WebC, you can probably skip this section!
It’s available on [npm as @11ty/webc](https://www.npmjs.com/package/@11ty/webc):
- ```
- npm install @11ty/webc
- ```
This is an ESM project and as such requires a "type": "module" in your package.json (or use the .mjs file extension).
- ```js
- import { WebC } from "@11ty/webc";
- ```
You _can_ use this in a CommonJS file via dynamic import:
- ```js
- (async function() {
- const { WebC } = await import("@11ty/webc");
- })();
- ```
Examples
JavaScript API
- ```js
- import { WebC } from "@11ty/webc";
- let page = new WebC();
- // This enables aggregation of CSS and JS
- // As of 0.4.0+ this is disabled by default
- page.setBundlerMode(true);
- // File
- page.setInputPath("page.webc");
- // Or, a String
- // page.setContent(`
Hello!
`); - let { html, css, js, components } = await page.compile();
- // Or, Readable Streams for each
- let { html, css, js } = await page.stream();
- ```
It’s HTML
- ```html
- <!doctype html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <title>WebC Example</title>
- </head>
- <body>
- WebC *is* HTML.
- </body>
- </html>
- ```
Uses [parse5](https://github.com/inikulin/parse5) to parse WebC HTML as modern browsers do (credit to @DasSurma’s work with Vite here)
* `` is optional (will be added automatically if the content starts with `Throws a helpful error if encounters quirks mode markup.HTML Imports (kidding… kinda)
To use components, we provide a few options: registering them globally via JavaScript or dynamically declaratively importing directly in your WebC file via webc:import.
Register global components
- ```js
- import { WebC } from "@11ty/webc";
- let page = new WebC();
- // Pass in a glob, using the file name as component name
- page.defineComponents("components/**.webc");
- // Array of file names, using file name as component name
- page.defineComponents(["components/my-component.webc"]);
- // Object maps component name to file name
- page.defineComponents({
- "my-component": "components/my-component.webc"
- });
- ```
And now you can use them in your WebC files without importing!
Consider this page.webc file:
- ```html
- <!doctype html>
- <title>WebC Example</title>
- <my-component></my-component>
- ```
If the components/my-component.webc file contains:
- ```html
- Components don’t need a root element, y’all.
- ```
Compiling page.webc will return the following HTML:
- ```html
- <!doctype html>
- <html>
- <head>
- <title>WebC Example</title>
- </head>
- <body>
- Components don’t need a root element, y’all.
- </body>
- </html>
- ```
Tricky trick: you aren’t limited to custom element names (e.g. my-component) here. You can use p, blockquote, h1, or any tag name to remap any HTML element globally. A more useful example might be an img component that uses the Eleventy Image utility to optimize all images in your project.
Dynamic import
Registering global components is _not_ required! You can use webc:import to dynamically import another component inline.
_Important note:_ webc: attributes are always removed from the resulting compiled markup.
page.webc:
- ```html
- <!doctype html>
- <title>WebC Example</title>
- <any-tag-name webc:import="components/my-component.webc"></any-tag-name>
- ```
_Another important note:_ We check for circular component dependencies and throw an error as expected if one is encountered.
New in WebC v0.6.2, you can import directly from an installed npm package. Here’s an example using a WebC component supplied by the Eleventy Syntax Highlighter plugin (4.2.0 or newer):
- ```html
- <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.
Remapping components
Use webc:is to remap a component to something else!
- ```html
- <div webc:is="my-component"></div>
- !-- equivalent to -->
- <my-component></my-component>
- ```
Component Markup
Keep that host component HTML
If you’d like to keep the host component element around, use webc:keep:
- ```html
- <my-component webc:keep></my-component>
- ```
Compiles to:
- ```html
- <my-component>Components don’t need a root element, y’all.</my-component>
- ```