Skip to content

Commit

Permalink
Update nextjs docs (#2080)
Browse files Browse the repository at this point in the history
  • Loading branch information
manuelc2209 committed Jun 28, 2024
1 parent 96edd85 commit 0aecf69
Showing 1 changed file with 105 additions and 7 deletions.
112 changes: 105 additions & 7 deletions docs/pages/tutorials/integrating-with-nextjs.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,12 @@ This page explains how to integrate Shoelace with a NextJS app.
This is a community-maintained document. Please [ask the community](/resources/community) if you have questions about this integration. You can also [suggest improvements](https://github.com/shoelace-style/shoelace/blob/next/docs/tutorials/integrating-with-nextjs.md) to make it better.
:::

## Requirements

This integration has been tested with the following:
## Instructions - Next 12.1.6

- Node: 16.13.1
- NextJS: 12.1.6
- Shoelace: 2.0.0-beta.74

## Instructions

To get started using Shoelace with NextJS, the following packages must be installed.

```bash
Expand Down Expand Up @@ -105,7 +101,109 @@ function MyApp({ Component, pageProps, URL }) {
}
```

### Environmental Variable
## Instructions - Next 14.2.4

- Node: v20.11.1
- NextJS: 14.2.4
- Shoelace: 2.15.1

To get started using Shoelace with NextJS, the following packages must be installed.

```bash
yarn add @shoelace-style/shoelace
```

### Importing the Default Theme

The next step is to import Shoelace's default theme (stylesheet) in your `_app.js` file:

```css
import '@shoelace-style/shoelace/dist/themes/light.css';
```

### Defining Custom Elements

After importing the theme, you'll need to import the JavaScript files for Shoelace. However, this is a bit tricky to do in NextJS thanks to the SSR environment not having any of the required browser APIs to define endpoints.

We'll want to create a component that uses [React's `useLayoutEffect`](https://reactjs.org/docs/hooks-reference.html#uselayouteffect) to add in the custom components before the first render:

```javascript
function CustomEls({ URL }) {
// useRef to avoid re-renders
const customEls = useRef(false);

useLayoutEffect(() => {
if (customEls.current) {
return;
}

import('@shoelace-style/shoelace/dist/utilities/base-path').then(({ setBasePath }) => {
setBasePath(`${URL}/static/static`);

// This imports all components
import('@shoelace-style/shoelace/dist/react');
// If you're wanting to selectively import components, replace this line with your own definitions

// import("@shoelace-style/shoelace/dist/components/button/button");
customEls.current = true;
});
}, [URL, customEls]);

return null;
}
```

:::tip
If we use `useEffect` instead of `useLayoutEffect`, the initial render will occur with the expected `sl-` props applied, but the subsequent render (caused by the `useEffect`) will remove those props as the custom components initialize. We _must_ use `useLayoutEffect` to have expected behavior
:::

:::tip
This will import all Shoelace components for convenience. To selectively import components, refer to the [Using webpack](/getting-started/installation#using-webpack) section of the docs.
:::

You may be wondering where the `URL` property is coming from. We'll address that in the next few sections.

### Using Our New Component CustomEls In Code

While we need to use `useLayoutEffect` for the initial render, NextJS will throw a warning at us for trying to use `useLayoutEffect` in SSR, which is disallowed. To fix this problem, we'll conditionally render the `CustomEls` component to only render in the browser

```javascript
function MyApp({ Component, pageProps, URL }) {
const isBrowser = typeof window !== 'undefined';
return (
<>
{isBrowser && <CustomEls URL={URL} />}
<Component {...pageProps} />
</>
);
}
```

### Importing Shoelace Components

After importing the customElement in your `_app.tsx` e.g., you now can import the components.

We will need to mark the component as 'use client'

```javascript
'use client';
import dynamic from 'next/dynamic';

const SlButton = dynamic(() => import('@shoelace-style/shoelace/dist/react/button'), {
loading: () => <p>Loading...</p>,
ssr: false
});

export default function Sample() {
return <SlButton>Button</SlButton>;
}
```

:::warning
Don't forget to mark your component to 'use client'.
:::

## Environmental Variable

However, to make `setBasePath()` work as-expected, we need to know where the file is hosted. To do this, we need to set [environmental variables](https://nextjs.org/docs/basic-features/environment-variables). Create a `.local.env` file and put the following inside:

Expand All @@ -129,7 +227,7 @@ MyApp.getInitialProps = async context => {
You'll need to set this `BASE_URL` variable inside the build process of whatever local build or CI/CD you have. This will need to be an absolute URL, as a relative URL will cause shoelace to throw a warning
:::

### webpack Config
## webpack Config

Next we need to add Shoelace's assets to the final build output. To do this, modify `next.config.js` to look like this.

Expand Down

0 comments on commit 0aecf69

Please sign in to comment.