Using 11ty and DecapCMS for 'non-blog' static websites -pt 2 Pages
Tags: webdev, jamstack, javascript, 11ty
Published: 2024-05-18 22:51:53

While there are plenty of examples for using 11ty and Decap CMS in blog settings, I struggled to find a way to make it work for a non-blog static website.

Leaving these tips out on the internet for anybody else looking to do the same.

## Making a static landing page editable in DecapCMS

This tip is for non markdown pages, such as landing pages that have unique structure and content that cant be edited in a WYSIWYG editor because of the complex underlying HTML structure that goes with the landing page.

I still needed to make all the text on this page editable so I decided to make them into strings that can be edited via the DecapCMS admin UI.

There might be a simpler approach but I went with loading all the text as frontmatter in a markdown file. Here is what my home landing page looks like 

**index.md**

```
---
title: Uplocal - Homepage
layout: home.liquid
hero-tagline: THE MARKETING OS for MULTI LOCATION BUSINESSES
hero-h1-firstline: Accelerate Local Demand
hero-h1-secondline: Elevate Customer Experience
hero-h1-thirdline: Collaborate Seamlessly
hero-signup-cta: See how <strong class="handwritten">XXXX</strong> can transform your local marketing
hero-signup-button: Try <strong>XXXX</strong>
leading-brands-headline: Trusted by Leading Brands
local-marketing-callout: Customer journeys are non-linear. Every touch point matters
// ... and so on
```
Every instance of text that should be editable in the admin is saved as a field in the front-matter. The rest of the file has no body content, just front-matter

The relevant template to use to render this page is also mentioned in the front-matter: 
`layout: home.liquid`

Then I added this page and all these fields to the collections array in the config.yml file for Decap under admin/config.yml

```
collections:
  - label: "Pages"
    name: "pages"
    files:
      - label: "Home"
        name: "home"
        file: "index.md"
        fields:
          - { label: Title, name: title, widget: string }
          - { label: Layout, name: layout, widget: hidden, default: home.html }
          - { label: hero-tagline, name: hero-tagline, widget: string }
          - {
              label: hero-h1-firstline,
              name: hero-h1-firstline,
              widget: string,
            }
          - {
              label: hero-h1-secondline,
              name: hero-h1-secondline,
              widget: string,
            }
          - {
              label: hero-h1-thirdline,
              name: hero-h1-thirdline,
              widget: string,
            }
          - { label: hero-signup-cta, name: hero-signup-cta, widget: string }
          - {
              label: hero-signup-button,
              name: hero-signup-button,
              widget: string,
            }
//... and so on
```
That makes these fields editable in the Admin UI

![Fields show up as strings in the Admin UI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hj9iurarpjonoe2tqt9l.png)

**On the template side:**

In the template for this page, the fields are referenced using template tags. EJS in my case

```
---
layout: layout.ejs
---
<section class="hero">
    <div class="content">
        <h2 class="callout">
            {{ hero-tagline }}
        </h2>
        <h1>
            <span>{{ hero-h1-firstline }}</span>
            <span>{{ hero-h1-secondline }}</span>
            <span>{{ hero-h1-thirdline }}</span>
        </h1>
        <div class="signup">
            <p>
                {{ hero-signup-cta }}
            </p>
            <form action="/signup">
                <input type="text" placeholder="Enter Email Address!" />
                <button type="submit">
                    {{ hero-signup-button }}
                </button>
            </form>
        </div>
    </div>
//... and so on
```

This line at the top in the front-matter of the template
`layout: layout.ejs`
tells 11ty that this template extends the layout.ejs tenplate to nest the landing page content inside the common header/footer frame that is also used for the rest of the site.