Adding amp-sidebar to a Next.js Blog
TL;DR
I still want a sidebar on mobile pages. And the current trend seems to be pressing a floating button to open a sidebar. Of course, using onClick would make the implementation easy, but onClick is not allowed under AMP.
This is where amp-sidebar comes in. However, there are few examples of using amp-sidebar with React or Next.js, and I couldn't find any examples combining it with Material-UI and TypeScript. I managed to implement it, so I'm leaving this article in hopes it helps someone.
amp-sidebar
It's hidden by default, appears when a button is pressed, and closes when you click outside the sidebar -- these features are built-in by default. Let's look at the official example:
Basically, you specify an id on the amp-sidebar, then set tap:{id}.toggle on the button's on attribute to enable opening and closing with that button. Besides toggle, the following actions are available:
| action | desc |
|---|---|
| open (default) | Opens the sidebar |
| close | Closes the sidebar |
| toggle | Toggles the sidebar |
Using toggle is generally sufficient.
So we know we need to write JSX like this:
However, note that the button element doesn't have an on attribute, so when using TypeScript, you need to define the on type (or you could use ts-ignore...).
Float Button
This part is easy -- just use @material-ui/core/Fab. However, the position isn't fixed by default, and on isn't defined, so those need to be configured.
For type definitions, we use xxxProps which is exported from the same module. In this case, import FabProps along with Fab. Since this button is intended to always use on, I haven't extended the default props.
AmpFab.tsx
Positioning could be defined here, but since I wanted to create an AmpSidebar component that combines amp-sidebar and AmpFab, I decided to define it there.
AmpSidebar (amp-sidebar + float button)
When the screen is large, a fixed sidebar is displayed, so the Fab is configured to appear only when the fixed sidebar is not shown. The CSS needed to fix it to the bottom-right is:
An important note is that amp-sidebar must be a direct child of <body>, so wrapping it in a <div> or similar will cause a warning. Therefore, it needs to be wrapped in a Fragment.
AmpSidebar.tsx
Importing into Layout
The default _document.js looks like this. This site states that ampsidebar needs to be placed directly in _document.js. However, <Main>, which is where page content goes, is wrapped in a Fragment, so placing amp-sidebar inside it won't trigger a warning. That said, wrapping it in Material-UI's Container or a simple div will trigger a warning, so amp-sidebar needs to be placed as high up in the component tree as possible.
_document.js
For example, you can do the following. Using this as the standard layout will prevent warnings.
Layout.tsx