Is your feature request related to a problem? Please describe.
When building a website I want pages to share a specific layout with common UI elements like a navigation, sidebar, footer, etc. Other pages might want to use different layouts like a custom landing page. This works fine as long as my landing page is not a sub page of an existing page with layout.
** MY SHOP **
src/routes
βββ bikes
β βββ _layout.svelte
β βββ category
β β βββ index.svelte
β βββ [slug]
β βββ index.svelte
β βββ _layout.svelte
In this example /bikes has a custom layout. Individual bike routes like /bikes/fancy-bike-3000 add their own layout and inherit the one from /bikes.
The problem appears when I want to make a super fancy landing page to promote all my mountain bikes. This page is completely individual and uses its own layout.
** MY SHOP **
src/routes
βββ bikes
β βββ _layout.svelte
β βββ category
β β βββ index.svelte
+ β β βββ mountain-bikes-promo
+ β β βββ index.svelte
β βββ [slug]
β βββ index.svelte
β βββ _layout.svelte
/bikes/category/mountain-bike-promo will always inherit the layout from /bikes, but in this case it's not wanted.
Sapper needs a feature to bail out of the layout inheritance and let sub pages define their own layouts.
Describe the solution you'd like
I would like an API that allows me as developer to get more flexibility when needed but has the layout inheritance by default.
Ideas:
<!-- _layout.svelte -->
<script>
export let inherit = false;
</script>
layout/ folder with custom layouts that you can specify in your page (https://nuxtjs.org/api/pages-layout). This probably doesn't work well with the current inheritance model but I like it./* vue code */
export default {
layout: 'blog',
// OR
layout (context) {
return 'blog'
}
}
Describe alternatives you've considered
In the end it's always possible to import layout components like any other component on every page. This provides full flexibility but can be a bit cumbersome if something like the inheritance model already exists.
A different solution could be to structure routes differently but a site structure should ideally not be constrained by the framework of choice.
How important is this feature to you?
I think this is a use case every application of a particular size will eventually run into. May it be custom landing pages or interactive stories with data visualizations.
Additional context
There was a former discussion in this issue https://github.com/sveltejs/sapper/issues/809.
The idea to hide elements in a root layout based on segment doesn't really work since not the full route is available.
Looking at my example bikes/_layout.svelte has segment === "category" but mountain-bike-promos is needed to know if layout components need to be hidden.
I look forward to any API discussion and can maybe come up with an implementation if this is a feature you want to integrate into Sapper.
I had the same request.
Would it be good that we introduce a reset-layout file __layout.svelte (note the double _), which means it will not inherit layouts up in the file tree, and all the child _layout.svelte will inherit up to it but stops here.
IMO, it is simple, clear, and consistent to the current layout mechanism.
@zwz I like the idea, but would reconsider the name. From a quick glance the difference between _ and __ isn't that big and it could look like a typo. It could cause some hard to debug issues where people see their layout not apply (or apply incorrectly) and don't find the issue because the difference between _layout.svelte and __layout.svelte isn't easily visible.
Maybe _root_layout.svelte could be used? This makes it super visible in a file tree, when a new route uses a new layout root. What do you think?
The idea to hide elements in a root layout based on segment doesn't really work since not the full route is available.
Looking at my example bikes/_layout.svelte has segment === "category" but mountain-bike-promos is needed to know if layout components need to be hidden.
That's because that is the segment and not the path (which could be removed in a future version, there is an issue discussing this). If you use the page store, then you have access to the entire path (see the Sapper documentation on stores()).
Regarding this request, this is something that has come up several times. There has been quite a bit of discussion around what the best way is to achieve this. Additional layouts in the relevant route folder would be in-keeping with how Sapper handles things, but it could be confusing having multiple layouts. If you wanted to 'disinherit' a parent layout, you would need to add blank 'reset' layouts, for example. This doesn't feel like an ideal solution to me.
I'm inclined to think that this kind of behaviour is better handled with a config file, but I know that Rich is (or at least has been) against adding a config file to Sapper. I am personally of the opinion that with the amount of CLI options we now have and with feature requests like this, a configuration file should be reconsidered.
One other option is to use a special layouts folder to 'shadow' specific layouts (or vice-versaβdefine them in a layouts file and shadow them in routes). This could work: custom layouts could be defined by matching the folder location and filename of the file you wish to customise which fits Sapper's routing model, but we would have another special folder. There are probably other problems with this too, what if you only want to 'disinherit' one of many layouts at an arbitrary depth gets weird, I can think of some partial solutions, but the resulting API would be confusing at best and limiting at worst.
If a config file is the best way to go then we need to have a conversation about whether or not we should have a configuration file in Sapper (and some related details) before this issue is tackled.
@pngwn could you elaborate how a config file would look like to solve this layout inheritance issue? Would there be a root config with a list of routes that inherit/don't inherit layouts?
For now I will make layout components and import them explicitly until there is a Sapper solution. I think that is what one would do in Next.js.
@pngwn could you elaborate how a config file would look like to solve this layout inheritance issue? Would there be a root config with a list of routes that inherit/don't inherit layouts?
No, I couldn't because I've given it approximately zero thought. But it seems like it might provide a relatively flexible solution.
Another idea:
<svelte:layout name="simple" />
or
<svelte:layout inherit={false} />
All the ideas proposed so far work for me.
@InstanceOfMichael I don't think this is an issue that should/can be solved in Svelte.
It only concerns how Sapper builds pages by building a Svelte component per page and nesting all _layout.svelte components on the way.
You can see that here https://github.com/sveltejs/sapper/blob/master/src/core/create_manifest_data.ts#L29
and here
https://github.com/sveltejs/sapper/blob/master/src/core/create_app.ts#L271.
If I use Svelte outside of Sapper, there is no concept of layout inheritance.
Throwing in my 2 sense...
Would it make sense to return a configuration object as part of the output of preload or another method like preload? That way you have a place in JS where you can make the decision on how a layout needs to behave. Hypothetically.
I like the idea of it being part of the route path as well. But this would give programatic control.
For example a blog post that is part of a series and should inherit the current layout, vs is not part of a series and should not.
@khrome83 I'm not sure if that is a possible solution. As I understand it preload get's called at runtime and the pages with all nested layouts are already compiled. That means the solution needs to happen at build time of the page components.
I think that the hole layout thing makes no sense, is better if each page imports the layout
I personally use this
//_layout.svelte => <slot></slot>
and have _root.svelte files that the pages can import instead of _layout.svelte
There is no layout in svelte why would be one in sapper?
Hello everyone, but maybe youβll make a type like this personβs, he added _reset.svelte ?
https://github.com/jakobrosenberg/svelte-filerouter
Any progress?
I found the routify (https://routify.dev/ ) approach very straightforward, if you have a _reset.svelte file on a folder, you use that and stop traversing the filesystem.
I don't get by there a 2 projects with so many similarities instead of one, it's a hard decision to make a choice between booth, I'm evaluating what to use for a very constrained device (a tv with a low end SOC), and using svelte instead of angular has bring a lot of improvement to the speed of the interface, but having to decide between so many options on routing is tiresome
I really like the _reset.svelte approach.
I am amazed Sapper does not yet have the ability to use multiple layouts.
Created a PR with _reset.svelte implementation: #1141
I actually quite like the _reset.svelte idea. It's a pretty simple convention. Can we call it _layout.reset.svelte or something like that?
@joycollector it appears there may need to be some more thought put into a solution for this.
As @pngwn pointed out:
but it could be confusing having multiple layouts. If you wanted to 'disinherit' a parent layout, you would need to add blank 'reset' layouts, for example. This doesn't feel like an ideal solution to me.
Likewise, what if one is nested three deep and wants to re-inherit the root layout. As much as I ::shudder:: at the thought of a config file to solve this, sadly π§ might be right.
Let's keep digging on solutions until we can hit something that answers all the right questions.
I'd favour the _reset approach over the config file one as it's visual and simple to manage.
A few things:
_layout.reset.svelte stops all the middle-hierarchy but still inherits the root, is a bit odd (non-obvious). Additionally, the only places I've ever wanted to do this, are places where I've not wanted the root layout._layout.reset.svelte was actually the new layout, and just indicated that the layout didn't inherit from it's ancestors. That might be what we're discussing, but I'm not sure.What about if layout files had an (optional) layout name:
root/
βββ _layout.svelte
βββ index.svelte
βββ subdir/
β βββ _layout.svelte // inherits from root
β βββ index.svelte
and then to manage inheritance:
root/
βββ _layout.a.svelte
βββ _layout.b.svelte
βββ index.svelte
βββ subdir/
β βββ _layout.a.svelte // inherits from a layout
β βββ index.svelte
β βββ /somedir
β β βββ _layout.b.svelte
β β βββ index.svelte // uses layout in same dir, and inherits from b layout (skips a)
β βββ /otherdir
β β βββ index.svelte // uses a layout a
This might be harder to express, however, but something along those lines would allow your layout choice not to depend on hierarchy.
@antony mmmm...interesting idea there, but I can poke holes in it. Which layout is the default? What if you want to use a particular layout, but don't need to change itβdoes that mean just putting an empty file with the same name in the nested folder? Seems an odd convention.
At first I liked the idea until I saw these holes. I am wondering though if this is closer...
@arxpoetica my intention was (and I didn't express it as I didn't want to muddy the waters), that it would work the same as it does now. The _layout.svelte would remain the default, and if it doesn't exist, there would be no layout (similar to how it is now). That gives you the flexibility of an automatic layout reset.
The behaviour of sub-directories would be similar. It's not unusual to have (in file-system based routing), a layout file which simply defines <slot></slot> to inherit a layout from a layer above. It's the same penalty you pay when using js files to duplicate content across URLs. It's a factor of file-system based routing - which I don't especially like, personally, but see the advantage of, for most applications.
I quite like the Routify way of doing it, just a _reset.svelte file in the folder you want to stop the inheritance in: https://github.com/sveltech/routify-starter/tree/master/src/pages/example/reset
Might it be a good idea to make the API cross-over as much as possible between the two projects? Maybe it's not something that's possible to do though.
Hi there, I am only learning sapper and svelte right now and I was browsing the web for a "sapper change layout", to discover the discussion is quite actual.
My contribution is quite probably stupid as I am an amateur developer, but as a professional UX designer I would have felt quite "natural" that any _layout.svelte file inside a child route folder would automatically reset the parent layout. Is it stupid ?
I was thinking such thing would be perfect as I want to change the background-color of the body.
Anyway... Keep up the awesome work !!
@elRomano it's not stupid IMO, for me it would also make sense if layouts wouldn't add up. We would be able to create different layout components and use them as desired in _layout.svelte. That way layout inheritance would be opt-in.
I think it should be easier but I did following for a personal project:
{#if segment === 'profile'}
<slot />
{:else}
<div>
.... main layout
{/if}
if the segment is profile it renders slot but the default is still my main layout, therefore I can use custom _layout.svelte for that segment.
Routify handles this problem really well with their _reset.svelte files. I'm currently trying to set up a login page which will completely differ from the standard global layout of the site and it's looking to be quite difficult in sapper.
@arxpoetica
Likewise, what if one is nested three deep and wants to re-inherit the root layout.
Is this an actual concern? I don't really think so, but could be wrong.
Also, if this is really needed, people can still have a root layout of
<MyLayout>
<slot/>
</MyLayout>
then just use _layout.reset on some nested elements and three deep do
<MyLayout>
<slot/>
</MyLayout>
again.
Most helpful comment
I really like the
_reset.svelteapproach.I am amazed Sapper does not yet have the ability to use multiple layouts.