Keeping persistent UI across routes with Gatsby's wrapPageElement
Tags: gatsby, react, intermediate
Published: 2021-03-12 16:57:40

---
title: Keeping persistent UI across routes with Gatsby's wrapPageElement
published: true
description:
tags: Gatsby, React, intermediate
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7fd9youclcrmlqz6zkg9.png
---

Nestled deep within Gatsby's docs, there's a couple of hella useful API functions: [`wrapPageElement`](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-browser/#wrapPageElement) and its big brother [`wrapRootElement`](https://www.gatsbyjs.com/docs/reference/config-files/gatsby-browser/#wrapRootElement).

These APIs give the opportunity to develop richer, complex UIs on top of Gatsby's static page generation.

By exporting these functions we can let Gatsby know how it should wrap additional components around our pages, both at the app's root level and nested one deeper at the page level.

![wrapPageAPIs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70zm85o3byoayykau9y9.png)

This comes in use when persisting components across routes, essential to some of the below features:

- Media Player / Controls
- Navigation elements
- Sidebars & Menus
- App-level context providers (like `Redux`)

> **In a rush? [Check out the quick implementation](https://github.com/miles-crighton/gatsby-persistent-ui).**

## **What do you mean by persist?**

Well, Gatsby's default behavior is to re-render all elements on a page whenever we change route.

As described above we may need components to stay alive and mounted across routes or _persist_.

In this article we're going to focus on using `wrapPageElement` to keep a layout component persistent across routes. There are multiple ways to do this, but I'm going to show you what I've found to be most elegant.

## **Assigning Layout Components**

What I'm calling a layout component can be any component that wraps around your page. A really basic example might include a header and a footer that sandwich your page's content.

```jsx
// components/Layout.js

export const Layout = ({ children }) => (
  <>
    <h1>My awesome site!</h1>
    {children}
    <footer>Built with Gatsby.</footer>
  </>
)
```

The sky's the limit with these layouts, anything that we want to keep alive across pages can be stuck into one. The only requirement is that it renders `{children}` so the wrapped page is visible.

We need to create a way of linking a layout component to a specific page component so that we can tell Gatsby how to correctly wrap it.

This is pretty easy, we'll just assign a static `Layout` property to our page component.

```jsx
// pages/index.js

import Layout from "../components/layout"

const IndexPage = () => {
  return ...
}

IndexPage.Layout = Layout
export default IndexPage
```

Notice `Layout` is uppercase just as a convention to indicate that we're working with a React component.

That's all that's required for the page, now onto Gatsby config.

## **Setting up our Gatsby files**

Now we need to tell Gatsby that we want it to wrap the page we've chosen with the assigned `Layout` component.

Within `gatsby-browser.js` and `gatsby-ssr.js` we can export `wrapPageElement`. When Gatsby calls this function for each page it passes it two arguments; an element and some props.

```js
// gatsby-browser.js && gatsby-ssr.js

export function wrapPageElement({ element, props }) {
  const Layout = element.type.Layout ?? React.Fragment
  return <Layout {...props}>{element}</Layout>
}
```

The element is simply the page component Gatsby wants to render, while the props is that page's props. These props include all kinds of useful data including any GraphQL queries made. ([Check out more here](https://www.gatsbyjs.com/docs/how-to/querying-data/page-query/))

We assign the `Layout` variable using the [nullish coalescing operator (??)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator) which checks if there's a Layout property on our page component, if not it just returns a [React fragment](https://reactjs.org/docs/fragments.html)

It's important that we spread the page's props onto the `Layout` so that any queries within the layout can be accessed via its own props.

**In almost all cases you'll want to keep your `gatsby-ssr` & `gatsby-browser` config files the same so that your components can correctly be [hydrated](https://www.gatsbyjs.com/docs/conceptual/react-hydration/).**

## **The result**

That's it! If we assign the same `Layout` to multiple pages and navigate between them Gatsby will make sure they're not re-rendered. This keeps any state within those layouts intact across routes.

I've put together a repo containing a minimal example showing how a counter component keeps counting when routes change. Check it out if you want to dig deeper.

[https://github.com/miles-crighton/gatsby-persistent-ui](https://github.com/miles-crighton/gatsby-persistent-ui)

What's great about this method is it scales to how ever many layouts you want while being completely opt-in.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ekogh48udf6i3a4ejls5.png)

If you don't want a layout on a page, don't set a `Layout` property - simple!