Component Model

Greenwood aims to support and optimize around the standard capabilities of the web platform and its features. In particular, the concept of using Web Components as a way to add and isolate interactivity and dynamic content into your application and that it can all be prerendered for you, just like you could do with any server side templating language.

The options for how to design your app effectively comes down to what you're trying to build, so if that's with the native HTMLElement or something based on it like LitElement (installed separately), Greenwood will take care of the rest.

Below are a couple examples to get you going.

Check out our README for more examples of sites built with Greenwood to see what's possible.

Example

Below is an example of creating a footer component using native HTMLElement within a page template of a Greenwood project. This is all just vanilla HTML / CSS / JS.

Component

Our component, in a file called src/components/footer.js could look like this

class FooterComponent extends HTMLElement {
  constructor() {
    super();

    // create a closed Shadow DOM
    this.root = this.attachShadow({ mode: 'closed' });
  }

  // run some code when the component is ready
  connectedCallback() {
    this.root.innerHTML = this.getTemplate();
  }

  // function can be called anything you want
  // return a string to be set to innerHTML, can include variable interpolation!
  getTemplate() {
    const year = new Date().getFullYear();

    return `<footer>This is the header component.  &copy; ${year}</footer>`;
  }
}

customElements.define('my-footer', FooterComponent);

You can use anything you want for the element's tag name (e.g. app-footer, x-footer, etc), it just needs to have a - in the name.

Usage

You can then use it within a page template.

<!DOCTYPE html>
<html lang="en" prefix="og:http://ogp.me/ns#">

  <head>
    <script type="module" src="/components/footer.js"></script>
  </head>

  <body>
    <my-footer></my-footer>
  </body>

</html>

Alternatives

An alternative like LitElement would work the same way.

Make sure you have installed LitElement with npm first!

src/components/greeting.js

import { html, LitElement } from 'lit';

class GreetingComponent extends LitElement {

  constructor() {
    super();
  }

  render() {
    return html`
      <div>
        <h1>Hello World!</h1>
      </div>
    `;
  }
}

customElements.define('x-greeting', GreetingComponent);
<!DOCTYPE html>
<html lang="en" prefix="og:http://ogp.me/ns#">

  <head>
    <script type="module" src="/components/greeting.js"></script>
  </head>

  <body>
    <x-greeting></x-greeting>
  </body>

</html>

References

Some notes / recommendations about ShadowDOM from our research

<h3>Content from inside the custom element. (inside HTMLElement)</h3>
<h3>
   <slot name="content"></slot> <!-- will show -->
<h3>
<div>
  <h3>
     <slot name="content"></slot> <!-- wont show -->
   <h3>
</div>