Rocket Logo Rocket Docs Themes Tools Blog

Layouts

Layouts are special in the sense that they output the full html page (including html, head, body, etc).

The simplest layout you can make is

import { html } from 'lit';

export const layout = data => html`
  <!DOCTYPE html>
  <html>
    <head>
      <title>Rocket</title>
    </head>
    <body>
      ${data.content()}
    </body>
  </html>
`;

and that will work fine, however, now every page will have the same title in the head.

If we now have the following markdown file:

# All about me

it will result in

<!DOCTYPE html>
<html>
  <head>
    <title>Rocket</title>
  </head>
  <body>
    <h1>All about me</h1>
  </body>
</html>

Now to define a title we can add it to the data object.

import { html } from 'lit';

export const layout = data => html`
  <!DOCTYPE html>
  <html>
    <head>
      <title>${data.title}</title>
    </head>
    <body>
      ${data.content()}
    </body>
  </html>
`;

If we want to have dynamic attributes/content for some tags outside of the body we will need to add a suffix. The suffix will be removed before writing the final html. For more details see the following lit issue.

In order to provide this data.title we now need to export it within the page. The code could look something like this.

```js server
export const title = 'About';
```

# All about me

results in

<!DOCTYPE html>
<html>
  <head>
    <title>About</title>
  </head>
  <body>
    <h1>All about me</h1>
  </body>
</html>

Layout function composition

Function can be composed into layouts.

const head = html`
  <link rel="icon" href="/favicon.ico" sizes="any" /><!-- 32x32 -->
  <link rel="icon" href="/icon.svg" type="image/svg+xml" />
  <link rel="apple-touch-icon" href="/apple-touch-icon.png" /><!-- 180x180 -->
  <link rel="manifest" href="/site.webmanifest" />
`;

const layoutA = data => html`
  <!DOCTYPE html>
  <html>
    <head>
      ${head}
      <title>${data.title}</title>
    </head>
    <body>
      ${data.content()}
    </body>
  </html>
`;

const layoutB =

Partial html is not supported in lit as it uses the browser build in html parser which trys to "auto correct" your html by closing tags. e.g. this

const mainStart = html`
  <main>
    <p>Always at the top</p>
`;

const mainEnd = html`
  </main>
`;

const layout = () => html`
  ${mainStart}
  <p>Hello World</p>
  ${mainEnd}
`;

will result in

<main>
  <p>Always at the top</p>
</main>
<p>Hello World</p>

Which is most likely not what you want.

Class based layouts

We can get the exact same result by using a class based layout.

import { html } from 'lit';

class MyLayout {
  render(data) {
    return html`
      <!DOCTYPE html>
      <html>
        <head>
          <title>${data.title}</title>
        </head>
        <body>
          ${data.content()}
        </body>
      </html>
    `;
  }
}

export const layout = new MyLayout();

With classes we also get the possibility to use options.

import { html } from 'lit';

class MyLayout {
  constructor(options) {
    this.options = {
      titleFn: originalTitle => `${originalTitle} - Rocket`,
    };
  }

  render(data) {
    return html`
      <!DOCTYPE html>
      <html>
        <head>
          <title>${this.options.titleFn(data.title)}</title>
        </head>
        <body>
          ${data.content()}
        </body>
      </html>
    `;
  }
}

export const layout = new MyLayout({
  titleFn: originalTitle => `${originalTitle} - Space Station`,
});
<!DOCTYPE html>
<html>
  <head>
    <title>About - Space Station</title>
  </head>
  <body>
    <h1>All about me</h1>
  </body>
</html>