Quick experiment with the Slinkity 11ty plugin
Tags: eleventy, javascript, jamstack, webdev
Published: 2021-10-22 13:01:12

---
title: Quick experiment with the Slinkity 11ty plugin
published: true
date: 2021-10-21 04:55:00 UTC
tags: eleventy, javascript, jamstack, webdev
canonical_url: https://bryanlrobinson.com/blog/quick-experiment-with-the-slinkity-11ty-plugin/
---

Ben Holmes (the creator of Slinkity) posted on Smashing Magazine today about [the creation of the Slinkity plugin for 11ty](https://www.smashingmagazine.com/2021/10/building-ssg-11ty-vite-jam-sandwich/). After reading it, I had to give [Slinkity](https://slinkity.dev/) a try.

## The use case

![My son's artwork with a like button above it saying there's 3 likes](https://cdn.sanity.io/images/myf3wh95/production/5e9a00728890decf2b962554a7138c77fbee093d-1656x1078.png)

My almost-6-year old has a little art website that I set up for him. Originally, it was just HTML. Then he made more art, so I converted to [11ty](https://11ty.dev) with a [Sanity Studio](https://sanity.io) for image management.

Like any adolescent, there's always a desire for more. He wanted a "like" button to know how many people liked his art. Despite explaining to him that I was really only sharing the site with his grandparents and that he wouldn't get too many likes. I promised I'd implement the feature if he consistently drew pictures for it.

He's done a good job, so I needed to write the feature...

Downside: I had no build process. Upside: A chance to see what folks were using for tiny interactions!

I reached out on Twitter to see what folks thought. Even on a weekend, there were opinions.

{% twitter 1446853552509489153 %}

From "[Roll your own in JS](https://twitter.com/jlengstorf/status/1446858170014437377)" to "[web components](https://twitter.com/jaredcwhite/status/1446857364716457986)" to "[petite vue](https://twitter.com/jeprisk/status/1446943436037242881)" and more. All great suggestions. I started with very simple JS event handlers, but it was pretty messy code. I moved on to a web component, but, as I usually do, I got frustrated by the feel of web components (I really want them to be awesome).

I want to learn more about [AstroJS](https://astro.build/), so I started re-writing the site in Astro (since there wasn't much functionality yet). It went relatively well, but the data pipeline is still pretty rough around the edges. I was able to get my Sanity content pulling in, but not without some annoyances (that the Astro discord helped me get through, I should add!).

Fast forward to Ben's post and my realization that Slinkity had the same ideas as AstroJS about islands of static content and rehydrated content (which I totally think is [the future of the web](https://twitter.com/brob/status/1450837487010598918)... and maybe it's the past, too...).

## The code

Expect a bigger tutorial on Slinkity coming up, but for now, here's a bit of code for how I implemented a very simple "Like" button for my son's images.

After I set up my Sanity connection, I had an `image.html` template that set up individual pagination for detail pages for each of the images – much like a blog post template. This is where I wanted the like button.

I kept things VERY simple (it's a site for a 6-year old after all!). Basically, a template to show an image with a caption. Quick aside, the `imageUrlFor` shortcode comes from my _alpha_ [Sanity Image plugin](https://www.sanity.io/plugins/11ty-sanity-image-helper).

```javascript
---
layout: "base.html"
pagination: 
    data: images
    size: 1
    alias: image
permalink: "{{ image.slug }}/index.html"
---

<div class="container">

    <figure class="stack">
        <img src="{% imageUrlFor image.image, 750 %}">
        <figcaption>{{ image.caption }}</figcaption>
    </figure>

</div>
```

Next, I needed to install the Slinkity package and change the way I was building and serving my site. What Slinkity does is creates a build process that runs your 11ty instance and then runs a [Vite](https://vitejs.dev/) server on the `_site` directory (or whatever your config file says is your output directory).

```sh
npm i --save-dev slinkity
```

```json
{
  // package.json
  "scripts": {
    // Start changes to slinkity --serve instead of eleventy --serve
    "start": "slinkity --serve",
    // Build changes to slinkity instead of eleventy
    "build": "slinkity"
  },
}
```

Once that was installed, I was ready to create a React component and insert it into my template.

### The component and the `react` shortcode

To add the component, I needed to create a `components` directory inside my `_includes` directory. In that directory, I added a `LikeCounter.js` file.

This code could probably be refined more, but at its essence it's a component that takes a current like count and an image ID (the Sanity document ID). It uses the count for initial HTML display (statically built during the build). It then fetches an updated count from a serverless function. The serverless function queries Sanity based on the document ID and gets the current count. I also have a serverless function for incrementing the count when a user clicks.

```javascript
import React, { useEffect, useState } from 'react'

function LikeCounter({likeCount, id}) {
  const [count, setCount] = useState(likeCount)
  useEffect(() => {
    fetch('/.netlify/functions/getLikes', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
            },
            body: JSON.stringify({image: id})
            })
            .then(res => res.json())
            .then(res => {
                setCount(res.count)
            })
                

  }, [])
  async function handleClick() {
    setCount(count + 1)

    fetch('/.netlify/functions/setLikes', {
          method: 'POST',
          body: JSON.stringify({
              image: id
              })
            })
            .then(res => res.json())
            .then(res => {
                console.log(res)
                setCount(res.count)
            })
}

  return (
    <div>
      <p>This photo has {count} likes ❤️ 
        <button onClick={handleClick}>Add a like</button>
      </p>   
    </div>
  )
}

export default LikeCounter
```

Once the component is created, I added the component to my template.

```javascript
---
layout: "base.html"
pagination: 
    data: images
    size: 1
    alias: image
permalink: "{{ image.slug }}/index.html"
---

<div class="container">

    {% react 'components/LikeCounter' 'likeCount' image.count 'id' image._id %}

    <figure class="stack">
        <img src="{% imageUrlFor image.image, 750 %}">
        <figcaption>{{ image.caption }}</figcaption>
    </figure>

</div>
```

The `react` shortcode accepts a number of arguments that will be ingested as props. In this case, I pass the `likeCount` and `id`.

Slinkity handles the rest.

In about an hour, I had a working React component and a new build pipeline. I got to keep all the things I love about 11ty.

## Why not Astro?

I'd originally planned on using this as a way to test and play with AstroJS. I really enjoyed playing with it in this use case, but the data pipeline was a bit rough to deal with for ingesting data from Sanity. I know the Astro team is currently working on the data pipeline, so I'm confident that for use cases like this it'll be a great solution soon.

More than anything Astro felt like a good bridge between the world of 11ty and the world of frameworks like Next. It felt kind of like I was writing Next code next to 11ty code, which was nice.

I think both these advancements are 100% the future. Slinkity gets the advantage of the current 11ty ecosystem and tooling.

## Next Steps

Right now Slinkity is just compatible with React, but I know the team is working on integrating with other libraries (and even vanilla JS, which I'm excited about!).

For now, I've got some additional ideas for using Slinkity to add more interactive islands with no need for a large build process, which is super exciting to me.