---
title: 'New features in v1'
date: 2021-08-07T15:32:14Z
tags: ['next-js', 'tailwind', 'guide']
draft: false
summary: 'An overview of the new features released in v1 - code block copy, multiple authors, frontmatter layout and more'
layout: PostSimple
---

## Overview

A post on the new features introduced in v1.0. New features:

<TOCInline toc={props.toc} exclude="Overview" toHeading={2} />

First load JS decreased from 43kB to 39kB despite all the new features added!

See [upgrade guide](#upgrade-guide) below if you are migrating from v0 version of the template.

## Theme colors

You can easily modify the theme color by changing the primary attribute in the tailwind config file:

```js:tailwind.config.js
theme: {
    colors: {
      primary: colors.teal,
      gray: colors.trueGray,
      ...
    }
  ...
}
```

The primary color attribute should be assigned an object with keys from 50, 100, 200 ... 900 and the corresponding color code values.

Tailwind includes great default color palettes that can be used for theming your own website. Check out [customizing colors documentation page](https://tailwindcss.com/docs/customizing-colors) for the full range of options.

Migrating from v1? You can revert to the previous theme by setting `primary` to `colors.sky` (Tailwind 2.2.2 and above, otherwise `colors.lightBlue`) and changing gray to `colors.coolGray`.

## Xdm MDX compiler

We switched the MDX bundler from [next-mdx-remote](https://github.com/hashicorp/next-mdx-remote) to [mdx-bundler](https://github.com/kentcdodds/mdx-bundler).
This uses [xdm](https://github.com/wooorm/xdm) under the hood, the latest micromark 3 and remark, rehype libraries.

**Warning:** If you were using custom remark or rehype libraries, please upgrade to micromark 3 compatible ones. If you are upgrading, please delete `node_modules` and `package-lock.json` to avoid having past dependencies related issues.

[xdm](https://github.com/wooorm/xdm) contains multiple improvements over [@mdx-js/mdx](https://github.com/mdx-js/mdx), the compiler used internally by next-mdx-remote, but there might be some breaking behaviour changes.
Please check your markdown output to verify.

Some new possibilities include loading components directly in the mdx file using the import syntax and including js code which could be compiled and bundled at the build step.

For example, the following jsx snippet can be used directly in an MDX file to render the page title component:

```js
import PageTitle from './PageTitle.js'
;<PageTitle> Using JSX components in MDX </PageTitle>
```

import PageTitle from './PageTitle.js'

<PageTitle> Using JSX components in MDX </PageTitle>

The default configuration resolves all components relative to the `components` directory.

**Note**:
Components which require external image loaders also require additional esbuild configuration.
Components which are dependent on global application state on lifecycle like the Nextjs `Link` component would also not work with this setup as each mdx file is built indepedently.
For such cases, it is better to use component substitution.

## Table of contents component

Inspired by [Docusaurus](https://docusaurus.io/docs/next/markdown-features/inline-toc) and Gatsby's [gatsby-remark-table-of-contents](https://www.gatsbyjs.com/plugins/gatsby-remark-table-of-contents/),
the `toc` variable containing all the top level headings of the document is passed to the MDX file and can be styled accordingly.
To make generating a table of contents (TOC) simple, you can use the existing `TOCInline` component.

For example, the TOC in this post was generated with the following code:

```js
<TOCInline toc={props.toc} exclude="Overview" toHeading={2} />
```

You can customise the headings that are displayed by configuring the `fromHeading` and `toHeading` props, or exclude particular headings
by passing a string or a string array to the `exclude` prop. By default, all headings that are of depth 3 or smaller are indented. This can be configured by changing the `indentDepth` property.
A `asDisclosure` prop can be used to render the TOC within an expandable disclosure element.

Here's the full TOC rendered in a disclosure element.

```js
<TOCInline toc={props.toc} asDisclosure />
```

<TOCInline toc={props.toc} asDisclosure />

## Layouts

You can map mdx blog content to layout components by configuring the frontmatter field. For example, this post is written with the new `PostSimple` layout!

### Adding new templates

layout templates are stored in the `./layouts` folder. You can add your React components that you want to map to markdown content in this folder.
The component file name must match that specified in the markdown frontmatter `layout` field.

The only required field is `children` which contains the rendered MDX content, though you would probably want to pass in the frontMatter contents and render it in the template.

You can configure the template to take in other fields - see `PostLayout` component for an example.

Here's an example layout which you can further customise:

```js
export default function ExampleLayout({ frontMatter, children }) {
  const { date, title } = frontMatter

  return (
    <SectionContainer>
      <div>{date}</div>
      <h1>{title}</h1>
      <div>{children}</div>
    </SectionContainer>
  )
}
```

### Configuring a blog post frontmatter

Use the `layout` frontmatter field to specify the template you want to map the markdown post to. Here's how the frontmatter of this post looks like:

```
---
title: 'New features in v1'
date: '2021-05-26   '
tags: ['next-js', 'tailwind', 'guide']
draft: false
summary: 'Introducing the new layout features - you can map mdx blog content to layout components by configuring the frontmatter field'
layout: PostSimple
---
```

You can configure the default layout in the respective page section by modifying the `DEFAULT_LAYOUT` variable.
The `DEFAULT_LAYOUT` for blog posts page is set to `PostLayout`.

### Extend

`layout` is mapped to wrapper which wraps the entire MDX content.

```js
export const MDXComponents = {
  Image,
  a: CustomLink,
  pre: Pre,
  wrapper: ({ components, layout, ...rest }) => {
    const Layout = require(`../layouts/${layout}`).default
    return <Layout {...rest} />
  },
}

export const MDXLayoutRenderer = ({ layout, mdxSource, ...rest }) => {
  const MDXLayout = useMemo(() => getMDXComponent(mdxSource), [mdxSource])

  return <MDXLayout layout={layout} components={MDXComponents} {...rest} />
}
```

Use the `MDXLayoutRenderer` component in a page where you want to accept a layout name to map to the desired layout.
You need to pass the layout name from the layout folder (it has to be an exact match).

## Analytics

The template now supports [plausible](https://plausible.io/), [simple analytics](https://simpleanalytics.com/) and google analytics.
Configure `siteMetadata.js` with the settings that correpond with the desired analytics provider.

```js
analytics: {
    // supports plausible, simpleAnalytics or googleAnalytics
    plausibleDataDomain: '', // e.g. tailwind-nextjs-starter-blog.vercel.app
    simpleAnalytics: false, // true or false
    googleAnalyticsId: '', // e.g. UA-000000-2 or G-XXXXXXX
  },
```

Custom events are also supported. You can import the `logEvent` function from `@components/analytics/[ANALYTICS-PROVIDER]` file and call it when
triggering certain events of interest. _Note_: Additional configuration might be required depending on the analytics provider, please check their official
documentation for more information.

## Blog comments system

We have also added support for [giscus](https://github.com/laymonage/giscus), [utterances](https://github.com/utterance/utterances) or disqus.
To enable, simply configure `siteMetadata.js` comments property with the desired provider and settings as specified in the config file.

```js
comment: {
    // Select a provider and use the environment variables associated to it
    // https://vercel.com/docs/environment-variables
    provider: 'giscus', // supported providers: giscus, utterances, disqus
    giscusConfig: {
      // Visit the link below, and follow the steps in the 'configuration' section
      // https://giscus.app/
      repo: process.env.NEXT_PUBLIC_GISCUS_REPO,
      repositoryId: process.env.NEXT_PUBLIC_GISCUS_REPOSITORY_ID,
      category: process.env.NEXT_PUBLIC_GISCUS_CATEGORY,
      categoryId: process.env.NEXT_PUBLIC_GISCUS_CATEGORY_ID,
      mapping: 'pathname', // supported options: pathname, url, title
      reactions: '1', // Emoji reactions: 1 = enable / 0 = disable
      // Send discussion metadata periodically to the parent window: 1 = enable / 0 = disable
      metadata: '0',
      // theme example: light, dark, dark_dimmed, dark_high_contrast
      // transparent_dark, preferred_color_scheme, custom
      theme: 'light',
      // theme when dark mode
      darkTheme: 'transparent_dark',
      // If the theme option above is set to 'custom`
      // please provide a link below to your custom theme css file.
      // example: https://giscus.app/themes/custom_example.css
      themeURL: '',
    },
    utterancesConfig: {
      // Visit the link below, and follow the steps in the 'configuration' section
      // https://utteranc.es/
      repo: process.env.NEXT_PUBLIC_UTTERANCES_REPO,
      issueTerm: '', // supported options: pathname, url, title
      label: '', // label (optional): Comment 💬
      // theme example: github-light, github-dark, preferred-color-scheme
      // github-dark-orange, icy-dark, dark-blue, photon-dark, boxy-light
      theme: '',
      // theme when dark mode
      darkTheme: '',
    },
    disqus: {
      // https://help.disqus.com/en/articles/1717111-what-s-a-shortname
      shortname: process.env.NEXT_PUBLIC_DISQUS_SHORTNAME,
    },
  },
```

## Multiple authors

Information on authors is now split from `siteMetadata.js` and stored in its own `data/authors` folder as a markdown file. Minimally, you will need to have a `default.md` file with authorship information. You can create additional files as required and the file name will be used as the reference to the author.

Here's how an author markdown file might looks like:

```md:default.md
---
name: Tails Azimuth
avatar: /static/images/avatar.png
occupation: Professor of Atmospheric Science
company: Stanford University
email: address@yoursite.com
twitter: https://twitter.com/Twitter
linkedin: https://www.linkedin.com
github: https://github.com
---

A long description of yourself...
```

You can use this information in multiple places across the template. For example in the about section of the page, we grab the default author information with this line of code:

```
const authorDetails = await getFileBySlug('authors', ['default'])
```

This is rendered in the `AuthorLayout` template.

### Multiple authors in blog post

The frontmatter of a blog post accepts an optional `authors` arrray field. If no field is specified, it is assumed that the default author is used. Simply pass in an array of authors to render multiple authors associated with post.

For example, the following frontmatter will display the authors given by `data/authors/default.md` and `data/authors/sparrowhawk.md`

```
title: 'My first post'
date: '2021-01-12'
draft: false
summary: 'My first post'
authors: ['default', 'sparrowhawk']
```

A demo of a multiple author post is shown in [Introducing Tailwind Nextjs Starter Blog post](/blog/introducing-tailwind-nextjs-starter-blog).

## Copy button for code blocks

Hover over a code block and you will notice a Github inspired copy button! You can modify `./components/Pre.js` to further customise it.
The component is passed to `MDXComponents` and modifies all `<pre>` blocks.

## Line highlighting and line numbers

Line highlighting and line numbers is now supported out of the box thanks to the new [rehype-prism-plus plugin](https://github.com/timlrx/rehype-prism-plus)

The following javascript code block:

````
```js {1, 3-4} showLineNumbers
var num1, num2, sum
num1 = prompt('Enter first number')
num2 = prompt('Enter second number')
sum = parseInt(num1) + parseInt(num2) // "+" means "add"
alert('Sum = ' + sum) // "+" means combine into a string
```
````

will appear as:

```js {1,3-4} showLineNumbers
var num1, num2, sum
num1 = prompt('Enter first number')
num2 = prompt('Enter second number')
sum = parseInt(num1) + parseInt(num2) // "+" means "add"
alert('Sum = ' + sum) // "+" means combine into a string
```

To modify the styles, change the following class selectors in the `tailwind.css` file:

```css
.code-line {
  @apply pl-4 -mx-4 border-l-4 border-gray-800;
}

.highlight-line {
  @apply -mx-4 bg-gray-700 bg-opacity-50 border-l-4 border-primary-500;
}

.line-number::before {
  @apply pr-4 -ml-2 text-gray-400;
  content: attr(line);
}
```

## Upgrade guide

There are significant portions of the code that has been changed from v0 to v1 including support for layouts and a new mdx engine.

There's also no real reason to change if the previous one serves your needs and it might be easier to copy
the component changes you are interested to your existing blog rather than migrating everything over.

Nonetheless, if you want to do so and have not changed much of the template, you could clone the new version and copy over the blog post over to the new template.

Another alternative would be to pull the latest tempate version with the following code:

```bash
git remote add template git@github.com:timlrx/tailwind-nextjs-starter-blog.git
git pull template v1 --allow-unrelated-histories
rm -rf node_modules
```

You can see an example of such a migration in this [commit](https://github.com/timlrx/timlrx.com/commit/bba1c185384fd6d5cdaac15abf802fdcff027286) for my personal blog.

v1 also uses `feed.xml` rather than `index.xml`, to avoid some build issues with vercel. If you are migrating you should add a redirect to `next.config.js` like so:

```
async redirects() {
  return [
    {
      source: '/:path/index.xml',
      destination: '/:path/feed.xml',
      permanent: true,
    }
  ]
}
```
