├── src
├── src.json
├── components
│ ├── hello-world.njk
│ └── components.json
├── _includes
│ ├── components
│ │ └── hello-world
│ │ │ ├── script.js
│ │ │ └── style.css
│ ├── page.njk
│ └── component.njk
├── app.css
└── index.njk
├── .gitignore
├── netlify.toml
├── .eleventy.js
├── package.json
└── README.md
/src/src.json:
--------------------------------------------------------------------------------
1 | {
2 | "layout": "page.njk"
3 | }
4 |
--------------------------------------------------------------------------------
/src/components/hello-world.njk:
--------------------------------------------------------------------------------
1 |
Hello World
--------------------------------------------------------------------------------
/src/components/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "layout": "component.njk",
3 | "permalink": "/components/{{ page.fileSlug }}.js",
4 | "tags": "components"
5 | }
6 |
--------------------------------------------------------------------------------
/src/_includes/components/hello-world/script.js:
--------------------------------------------------------------------------------
1 | const hw = shadowRoot.querySelector(".hello-world");
2 |
3 | setTimeout(() => {
4 | hw.classList.add('hello-world__visible');
5 | }, 1000);
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies installed by npm
2 | node_modules
3 |
4 | # build artefacts
5 | public
6 |
7 | # secrets and errors
8 | .env
9 | .log
10 |
11 | # macOS related files
12 | .DS_Store
--------------------------------------------------------------------------------
/src/_includes/components/hello-world/style.css:
--------------------------------------------------------------------------------
1 | .hello-world {
2 | background-color: var(--hw-bgcolor, rgb(25, 25, 155));
3 | color: var(--hw-color, white);
4 | font-size: var(--hw-font-size, 3rem);
5 | text-align: var(--hw-text-align, center);
6 | opacity: 0;
7 | transition: opacity 180ms ease-in;
8 | }
9 |
10 | .hello-world__visible {
11 | opacity: 1;
12 | }
13 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | # Directory to change to before starting a build.
3 | # This is where we will look for package.json/.nvmrc/etc.
4 | base = ""
5 |
6 | # Directory (relative to root of your repo) that contains the deploy-ready
7 | # HTML files and assets generated by the build. If a base directory has
8 | # been specified, include it in the publish directory path.
9 | publish = "public"
10 |
11 | # Default build command.
12 | command = "npm run build"
--------------------------------------------------------------------------------
/src/_includes/page.njk:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ title }}
7 |
8 |
9 |
10 |
13 |
14 | {{ content | safe }}
15 |
16 |
17 | {%- if component %}
18 | {% set componentUrl %}/components/{{ component}}.js{% endset %}
19 |
20 | {% endif -%}
21 |
22 |
--------------------------------------------------------------------------------
/.eleventy.js:
--------------------------------------------------------------------------------
1 | module.exports = function (eleventyConfig) {
2 | // Optional, used for the main application styles
3 | eleventyConfig.addWatchTarget("./src/app.css");
4 | eleventyConfig.addPassthroughCopy("./src/app.css");
5 |
6 | // Allows transforming ex. `hello-world` into `HelloWorld`
7 | // for the component `class` export
8 | eleventyConfig.addFilter("createClass", (str) => {
9 | if (!str) {
10 | return;
11 | }
12 | return str.split('-').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join('');
13 | });
14 |
15 | return {
16 | dir: {
17 | input: "src",
18 | output: "public",
19 | },
20 | };
21 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "11ty-web-component-generator",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "eleventy --serve",
8 | "build": "eleventy"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/5t3ph/11ty-web-component-generator.git"
13 | },
14 | "keywords": [
15 | "11ty",
16 | "eleventy",
17 | "web components",
18 | "custom elements"
19 | ],
20 | "author": "5t3ph",
21 | "license": "ISC",
22 | "dependencies": {
23 | "@11ty/eleventy": "^0.11.0"
24 | },
25 | "browserslist": [
26 | "last 2 versions"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/src/_includes/component.njk:
--------------------------------------------------------------------------------
1 | {%- set componentName = page.fileSlug %}
2 | {%- set componentClass = page.fileSlug | createClass %}
3 | {%- set componentScript %}components/{{componentName}}/script.js{% endset %}
4 | {%- set componentCss %}components/{{componentName}}/style.css{% endset -%}
5 |
6 | export class {{ componentClass }} extends HTMLElement {
7 | constructor() {
8 | super();
9 |
10 | this.attachShadow({ mode: "open" });
11 | }
12 |
13 | connectedCallback() {
14 |
15 | const { shadowRoot } = this;
16 |
17 | shadowRoot.innerHTML = `
18 |
24 | {{ content | safe}}
25 | `;
26 | {% include componentScript %}
27 | }
28 | }
29 |
30 | window.customElements.define("{{ componentName }}", {{ componentClass }});
--------------------------------------------------------------------------------
/src/app.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | font-family: system, -apple-system, ".SFNSText-Regular", "San Francisco",
7 | "Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif;
8 | color: #222;
9 | width: 80ch;
10 | max-width: 100%;
11 | margin: 0 auto;
12 | padding: 0 1.25rem;
13 | line-height: 1.5;
14 | }
15 |
16 | h1,
17 | code,
18 | a {
19 | color: rgb(25, 25, 155);
20 | }
21 |
22 | .button {
23 | background-color: rgb(25, 25, 155);
24 | color: #fff;
25 | text-decoration: none;
26 | padding: 0.25em 0.5em;
27 | border-radius: 0.15em;
28 | font-size: 1.125rem;
29 | display: inline-flex;
30 | }
31 |
32 | h1 {
33 | line-height: 1;
34 | margin-left: -0.5rem;
35 | }
36 |
37 | small {
38 | color: #777;
39 | }
40 |
41 | code {
42 | font-weight: bold;
43 | font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console",
44 | "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono",
45 | "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier,
46 | monospace;
47 | }
48 |
49 | pre {
50 | background-color: #f9f9f9;
51 | border: 1px solid #eee;
52 | border-radius: 4px;
53 | padding: 0.5em;
54 | overflow-x: auto;
55 | }
56 |
57 | pre,
58 | code {
59 | font-size: 0.9rem;
60 | }
61 |
62 | pre code {
63 | font-size: inherit;
64 | line-height: 1.3;
65 | }
66 |
67 | hello-world {
68 | /* Custom variables can pierce the shadow DOM to style web components */
69 | /* --hw-color: yellow; */
70 | }
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # ⚡️ 11ty Web Component Generator
4 |
5 | > [View the demo Hello World component >](https://11ty-web-component-generator.netlify.app/)
6 |
7 | ## Using the Generator
8 |
9 | [Eleventy (11ty) is a static site generator](https://www.11ty.dev/docs/) that makes it possible to mix templating languages. More importantly to this generator is that we can customize the _output file type_ and composite a file from _includes_.
10 |
11 | The web components are generated within a Nunjucks (`.njk`) template that outputs the final `.js` file.
12 |
13 | This generator works with the inherent features of Eleventy, including that it expects templates and template partials to be placed in `_includes`.
14 |
15 | This leads to the following file structure to create a web component with styles and additional scripting.
16 |
17 | First, create the component template file in `src/components/[component-name].njk`. _It is important to kebab-case the file name_
18 |
19 | Then within `_includes/components/` create:
20 |
21 | ```bash
22 | [component-name]/
23 | script.js
24 | style.css
25 | ```
26 |
27 | Keep the names of `script.js` and `style.css` so that the `_includes/component.njk` template can successfully include their contents to generate the web component.
28 |
29 | ## Using a Generated Web Component
30 |
31 | The final web component will be output within `public/components/[component-name].js` and is ready to be included in another project such as:
32 |
33 | ```html
34 |
35 |
36 | ```
37 |
38 | ### Display a Component Within This Generator Project
39 |
40 | Create additional pages in this project directly within `src` as Nunjuck (`.njk`) files and add the following frontmatter in addition to any HTML and Nunjuck template tags.
41 |
42 | ```md
43 | title: Page Title
44 | component: component-name
45 | ```
46 |
47 | Then the `page.njk` template will use the `component` value to include the relative path to the web component script.
48 |
49 | ## Project Scripts
50 |
51 | - **`npm start`** - run Eleventy on localhost with included Browsersync hot-reload
52 | - **`npm run build`** - run only Eleventy for creating a production build of the generator project
53 |
54 | ## Web Component Resources
55 |
56 | First a little disclaimer - I am brand new to web components, so I know this doesn't cover all the things you may want to do, or the best way to generically composite them. Submit a PR if you want to help extend this generator!
57 |
58 | Here are some resources that helped me put together [my first web component](https://github.com/5t3ph/css-webring):
59 |
60 | - [Encapsulating Style and Structure with Shadow DOM](https://css-tricks.com/encapsulating-style-and-structure-with-shadow-dom/)
61 | - [Using custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#Working_through_some_simple_examples)
62 | - [Creating a Custom Element from Scratch](https://css-tricks.com/creating-a-custom-element-from-scratch/)
63 | - [Custom Elements v1: Reusable Web Components](https://developers.google.com/web/fundamentals/web-components/customelements)
64 |
65 | ## 11ty Resources
66 |
67 | I'm very fond of 11ty, so here's a list of my other resources:
68 |
69 | **Learn to build an 11ty site in 20 mins** with my [egghead video course](https://5t3ph.dev/learn-11ty) and see how to add a blog and custom data.
70 |
71 | **Add auto-generated social media images** by following [my tutorial](https://dev.to/5t3ph/automated-social-sharing-images-with-puppeteer-11ty-and-netlify-22ln)
72 |
73 | **Explore advanced setup of custom data** through my [tutorial on building a community site](https://css-tricks.com/a-community-driven-site-with-eleventy-building-the-site/)
74 |
75 | **For a full-featured starter** check out my [11ty Netlify Jumpstart](https://11ty-netlify-jumpstart.netlify.app/) (also works for hosts other than Netlify).
76 |
77 | **For a featureless Sass starter** grab the template for my [11ty Sass Skeleton](https://github.com/5t3ph/11ty-sass-skeleton)
78 |
--------------------------------------------------------------------------------
/src/index.njk:
--------------------------------------------------------------------------------
1 | ---
2 | title: ⚡️ 11ty Web Component Generator
3 | component: hello-world
4 | ---
5 | {# Using Nunjucks to avoid Markdown wrapping the web component in a paragraph tag #}
6 |
7 | Made by Stephanie Eckles - @5t3ph
8 |
9 | Fork on GitHub
10 |
11 | Demo Component: Hello World
12 |
13 | This very basic component will display a "Hello World" banner 1 second after load.
14 |
15 |
16 |
17 | Using the Generator
18 |
19 | Eleventy (11ty) is a static site generator that makes it possible to mix templating languages. More importantly to this generator is that we can customize the output file type and composite a file from includes .
20 |
21 | The web components are generated within a Nunjucks (.njk) template that outputs the final .js file.
22 |
23 | This generator works with the inherent features of Eleventy, including that it expects templates and template partials to be placed in _includes.
24 |
25 | This leads to the following file structure to create a web component with styles and additional scripting.
26 |
27 | First, create the component template file in src/components/[component-name].njk. It is important to kebab-case the file name
28 |
29 | Then within _includes/components/ create:
30 |
31 |
32 |
33 | [component-name]/
34 | script.js
35 | style.css
36 |
37 |
38 |
39 | Keep the names of script.js and style.css so that the _includes/component.njk template can successfully include their contents to generate the web component.
40 |
41 | Using a Generated Web Component
42 |
43 | The final web component will be output within public/components/[component-name].js and is ready to be included in another project such as:
44 |
45 |
46 |
47 | {{ '' }}
48 | {{ ' ' }}
49 |
50 |
51 |
52 | Fork on GitHub
53 |
54 | Display a Component Within This Generator Project
55 |
56 | Create additional pages in this project directly within src as Nunjuck (.njk) files and add the following frontmatter in addition to any HTML and Nunjuck template tags.
57 |
58 |
59 |
60 | {{ 'title: Page Title' }}
61 | {{ 'component: component-name' }}
62 |
63 |
64 |
65 | Then the page.njk template will use the component value to include the relative path to the web component script.
66 |
67 | Project Scripts
68 |
69 |
70 | npm start - run Eleventy on localhost with included Browsersync hot-reload
71 | npm run build - run only Eleventy for creating a production build of the generator project
72 |
73 |
74 | Web Component Resources
75 |
76 | First a little disclaimer - I am brand new to web components, so I know this doesn't cover all the things you may want to do, or the best way to generically composite them. Submit a PR if you want to help extend this generator!
77 |
78 | Here are some resources that helped me put together my first web component :
79 |
80 |
86 |
87 | 11ty Resources
88 |
89 | I'm very fond of 11ty, so here's a list of my other resources:
90 |
91 | Learn to build an 11ty site in 20 mins with my egghead video course and see how to add a blog and custom data.
92 |
93 | Add auto-generated social media images by following my tutorial
94 |
95 | Explore advanced setup of custom data through my tutorial on building a community site
96 |
97 | For a full-featured starter check out my 11ty Netlify Jumpstart (also works for hosts other than Netlify).
98 |
99 | For a featureless Sass starter grab the template for my 11ty Sass Skeleton
--------------------------------------------------------------------------------