Create a blog with Sapper & Markdown: Tagging
Tags: svelte, javascript, showdev
Published: 2020-10-29 06:58:21

---
title: Create a blog with Sapper & Markdown: Tagging
published: true
description: Add tagging to blog posts
tags: svelte, javascript, showdev
series: Create a blog with Sapper & Markdown 
//cover_image: https://direct_url_to_image.jpg
---

When dealing with lots of content, it's a good idea to have some categorization. One versatile approach to categorization is tagging. Nearly all blogs use it, and ours will too.

Note: If you prefer to watch rather than read, there's a screencast version here: https://youtu.be/PGLsFfBf1UA

## Adding metadata

Continuing from [Part 1](https://dev.to/joshnuss/create-a-blog-with-markdown-sapper-50ad), our blog repo has a `/posts` folder filled with Markdown files. Our first step will be to add a new field called `tags` to the "front matter" metadata in each markdown file.

```diff
---
title: Example Post
date: 2020-10-28
+tags: hello, world
---

# Example Title

...
```

## Parsing tags

Sine the `tags` string is comma-delimited, it will need to be converted into to an array during the parsing phase.

```js
// in src/posts.js
// transform is called once for each post
function transform({metadata}) {
  ...
  
  // the `tags` field is optional, so default to empty list
  let tags = []

  // check if `tags` field is defined on this post
  if (metadata.tags) {
    // split the tags string by comma, and trim away any extra spaces
    tags = metadata.tags.split(',').map(str => str.trim())
  }

  // return previous data and tags 
  return {...metadata, tags}
}
```

# Listing tags

Now that each post has a cleaned up `tags` array. It's ready to be displayed on the `/post/:permalink` page. 

```diff
<!-- src/routes/posts/[permalink].svelte -->
<script>...</script>

<h1>{post.title}</h1>

<!-- new component to show tag list -->
+<Tags tags={post.tags}/>

{@html post.html}
```

And the new `<Tags/>` component will be defined as:

```html
<!-- src/components/Tags.svelte -->
<script>
  // take in tags as a prop
  export let tags
</script>

<nav>
  <!-- iterate through each tag -->
  {#each tags as tag}
    <!-- link each tag to /tag/:tag page -->
    <a href="/tag/{tag}">#{tag}</a>
  {/each}
</nav>
```

## Listing posts by tag

To show all the posts for a given tag, we'll need a new page and some JavaScript logic to filter posts by tag.

First, lets define the `findByTag()` function. It will take the `tag` as a parameter and return the list of posts matching the tag.

```js
// src/posts.js
export function findByTag(tag) {
  // filter out all posts that don't include the tag
  return posts.filter(post => !post.tags.includes(tag))
}
```

Then, define new page for `/tag/:tag` that will use `findByTag()` to locate posts:

```html
<!-- src/routes/tag/[tag].svelte -->
<script context="module">
  import { findByTag } from '@/posts'
  
  export function preload(page) {
    // extract tag param
    const { tag } = page.params
    // find posts based on tag param
    const posts = findByTag(tag)

    // return props
    return { tag, posts }
  }
</script>

<script>
  // props are provided by preload() function
  export let tag, posts
</script>

<!-- show #tag as title -->
<h1>#{tag}</h1>

{#each posts as post}
  <!-- show each post -->
{/each}
```

## Extracting a <PostList/> component

Lastly, since we are showing the list of posts on 2 pages `/tag/:tag` and `/post/:permalink`, it would be to avoid duplication and have a reusable component for listing posts. This will make it easier to adjust and style down the road.

```html
<!-- src/components/PostList.svelte -->
<script>
  // it takes an array of posts as a prop
  export let posts
</script>

<!-- iterate thru each post and output an <article> tag -->
{#each posts as post}
  <article>
    <!-- link to /posts/:permalink page -->
    <a href={`/posts/${post.permalink}`}>
      <h2>{post.title}</h2>
      <p>{post.summary}</p>
    </a>
  </article>
{/each}
```

And then update the pages `src/routes/posts/[permalink].svelte` and `src/routes/tag/[tag].svelte` to use `<PostList/>` instead of  `{#each}`.

```html
<!-- use our new shiny component -->
<PostList {posts}/>
```

## Summary

Our little blog is getting better! Now that we have tagging working, in the next post we'll explore adding syntax highlighting.

You can find all the code here:
https://github.com/joshnuss/blog-template

Happy coding! ✌

# Screencast

{% youtube PGLsFfBf1UA %}