I've been poking at Remix as a SSR framework. It appeals because I agree with the philosophy: react focused, leaning into web standards, and with good developer UX.
But, similar to other convention-based frameworks, I quickly ran into a situation where I knew how to write the code but not how to implement it via convention.
The site I'm building with Remix shares a layout between the index and its sub-pages. Essentially the index /
route is the home, and shares its layout with any /subpage
.
Basically:
What Doesn't Work
Naively, I started building out a layout with this file structure:
routes/
└── index.tsx
└── subpage.tsx
But remix considers /subpage
a peer, of /
, even if the url reads like subpage
is a child of /
. And so the subpage route contains none of the shared layout defined in the index file.
So clearly the index.tsx
file is not the right place to put shared layout code. But where?
What Does Work
The remix documentation has two other concepts that compose to solve this problem, layout routes and pathless routes.
Layout Routes
A layout route is a file with the same name as a directory:
routes/
├── app
│ ├── index.tsx # <-- page rendered inside layout
│ └── subpage.tsx # <-- page rendered inside layout
├── app.tsx # <--- the layout file
└── index.tsx
But that alone doesn't solve my problem unless I want the entire app to exist at a nested route /app
(or whatever). I don't.
Pathless Routes
The second concept is the pathless route, which is any folder that starts with __
. This allows you to create nesting in the filesystem that isn't reflected in the url, for example:
routes/
├── app
│ ├── __admin
│ │ ├── admin-login.tsx # <-- renders at /app/admin-login
│ │ └── moderation.tsx # <-- renders at /app/moderation
│ ├── page1.tsx # <-- renders at /app/page1
│ └── page2.tsx # <-- renders at /app/page2
├── app.tsx
└── index.tsx # <-- renders at /
Combining the Two with Index Pages
Frankly, I didn't expect combining pathless and layout routes to work to work with index
pages, as index pages are usually a bit special in that they're usually expect to exist as files not directories. And especially not as directories starting with __
!
But--credit to remix--the rules here compose well with indexes just as well as they do with other pages and routes. Applying the rules above, I ended up with:
routes/
├── __index
│ ├── index.tsx
│ └── subpage.tsx
└── __index.tsx
Which renders exactly like you think it might:
Code
You can checkout code for the example above on Github.
Discussion (2)
Any reason you didn't use
root.tsx
?Simplified example above, but some of the other pages don't share that layout. Putting layout in the root was causing it to show up everywhere. I miss something?