-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Implement new layouts system #6174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 39 commits
2a237eb
f47c3fb
d145557
de383f9
faee0df
d6fba37
bb5ed6e
02efc1e
d2d3000
bdaa71c
6419645
6e04821
ffb8a8a
907f080
8229811
0a72369
84e266f
2bd5203
0b52b1d
ce66e0d
74433e5
e9bf361
3287b04
e4aa3a2
afe4cd4
7322c10
cb262ff
0ea2976
fa5c424
0acae38
8ea3c40
891b319
872a291
eef4be5
314ebe3
5687d7a
4bf6184
cb47d7f
fbb40a7
0945723
0018d97
2d421b5
d39e33c
1b106fa
8bba42d
dcf2ace
7c74aa9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@sveltejs/kit': patch | ||
--- | ||
|
||
[breaking] implement new layout system | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,75 +126,66 @@ assert.equal( | |
|
||
To express a `%` character, use `%25`, otherwise the result will be malformed. | ||
|
||
### Named layouts | ||
### Advanced layouts | ||
|
||
Some parts of your app might need something other than the default layout. For these cases you can create _named layouts_... | ||
By default, the _layout hierarchy_ mirrors the _route hierarchy_. In some cases, that might not be what you want. | ||
|
||
```svelte | ||
/// file: src/routes/+layout-foo.svelte | ||
<div class="foo"> | ||
<slot></slot> | ||
</div> | ||
``` | ||
#### (group) | ||
|
||
...and then use them by referencing the layout name (`foo`, in the example above) in the filename: | ||
Perhaps you have some routes that are 'app' routes that should have one layout (e.g. `/dashboard` or `/item`), and others that are 'marketing' routes that should have a different layout (`/blog` or `/testimonials`). We can group these routes with a directory whose name is wrapped in parentheses — unlike normal directories, `(app)` and `(marketing)` do not affect the URL pathname of the routes inside them: | ||
|
||
```svelte | ||
/// file: src/routes/my-special-page/[email protected] | ||
<h1>I am inside +layout-foo</h1> | ||
```diff | ||
src/routes/ | ||
+│ (app)/ | ||
│ ├ dashboard/ | ||
│ ├ item/ | ||
│ └ +layout.svelte | ||
+│ (marketing)/ | ||
│ ├ about/ | ||
│ ├ testimonials/ | ||
│ └ +layout.svelte | ||
├ admin/ | ||
└ +layout.svelte | ||
``` | ||
|
||
> Named layout should only be referenced from Svelte files | ||
|
||
Named layouts are very powerful, but it can take a minute to get your head round them. Don't worry if this doesn't make sense all at once. | ||
You can also put a `+page` directly inside a `(group)`, for example if `/` should be an `(app)` or a `(marketing)` page. | ||
|
||
#### Scoping | ||
#### +page@ | ||
|
||
Named layouts can be created at any depth, and will apply to any components in the same subtree. For example, `+layout-foo` will apply to `/x/one` and `/x/two`, but not `/x/three` or `/four`: | ||
Conversely, some routes of your app might need to break out of the layout hierarchy. Let's add an `/item/[id]/embed` route inside the `(app)` group from the previous example: | ||
|
||
```bash | ||
```diff | ||
src/routes/ | ||
├ x/ | ||
│ ├ +layout-foo.svelte | ||
│ ├ one/[email protected] # ✅ page has `@foo` | ||
│ ├ two/[email protected] # ✅ page has `@foo` | ||
│ └ three/+page.svelte # ❌ page does not have `@foo` | ||
└ four/[email protected] # ❌ page has `@foo`, but +layout-foo is not 'in scope' | ||
├ (app)/ | ||
│ ├ item/ | ||
│ │ ├ [id]/ | ||
│ │ │ ├ embed/ | ||
+│ │ │ │ └ +page.svelte | ||
│ │ │ └ +layout.svelte | ||
│ │ └ +layout.svelte | ||
│ └ +layout.svelte | ||
└ +layout.svelte | ||
``` | ||
|
||
#### Inheritance chains | ||
|
||
Layouts can themselves choose to inherit from named layouts, from the same directory or a parent directory. For example, `x/y/[email protected]` is the default layout for `/x/y` (meaning `/x/y/one`, `/x/y/two` and `/x/y/three` all inherit from it) because it has no name. Because it specifies `@root`, it will inherit directly from the nearest `+layout-root.svelte`, skipping `+layout.svelte` and `x/+layout.svelte`. | ||
Ordinarily, this would inherit the root layout, the `(app)` layout, the `item` layout and the `[id]` layout. We can reset to one of those layouts by appending `@` followed by the segment name — or, for the root layout, the empty string. In this example, we can choose from `[email protected]`, `+page@(app).svelte`, `[email protected]` or `+page@[id].svelte`: | ||
|
||
``` | ||
```diff | ||
src/routes/ | ||
├ x/ | ||
│ ├ y/ | ||
│ │ ├ [email protected] | ||
│ │ ├ one/+page.svelte | ||
│ │ ├ two/+page.svelte | ||
│ │ └ three/+page.svelte | ||
├ (app)/ | ||
│ ├ item/ | ||
│ │ ├ [id]/ | ||
│ │ │ ├ embed/ | ||
+│ │ │ │ └ +page@(app).svelte | ||
│ │ │ └ +layout.svelte | ||
│ │ └ +layout.svelte | ||
│ └ +layout.svelte | ||
├ +layout.svelte | ||
└ +layout-root.svelte | ||
└ +layout.svelte | ||
``` | ||
|
||
> In the case where `+layout-root.svelte` contains a lone `<slot />`, this effectively means we're able to 'reset' to a blank layout for any page or nested layout in the app by adding `@root`. | ||
#### +layout@ | ||
|
||
If no parent is specified, a layout will inherit from the nearest default (i.e. unnamed) layout _above_ it in the tree. In some cases, it's helpful for a named layout to inherit from a default layout _alongside_ it in the tree, such as `+layout-root.svelte` inheriting from `+layout.svelte`. We can do this by explicitly specifying `@default`, allowing `/x/y/one` and siblings to use the app's default layout without using `x/+layout.svelte`: | ||
Like pages, layouts can _themselves_ break out of their parent layout hierarchy, using the same technique. For example, a `+layout@.svelte` component would reset the hierarchy for all its child routes. | ||
|
||
```diff | ||
src/routes/ | ||
├ x/ | ||
│ ├ y/ | ||
│ │ ├ [email protected] | ||
│ │ ├ one/+page.svelte | ||
│ │ ├ two/+page.svelte | ||
│ │ └ three/+page.svelte | ||
│ └ +layout.svelte | ||
├ +layout.svelte | ||
-└ +layout-root.svelte | ||
+└ [email protected] | ||
``` | ||
#### When to use layout groups | ||
|
||
> `default` is a reserved name — in other words, you can't have a `+layout-default.svelte` file. | ||
Not all use cases are suited for layout grouping, nor should you feel compelled to use them. It might be that your use case would result in complex `(group)` nesting, or that you don't want to introduce a `(group)` for a single outlier. It's perfectly fine to use other means such as composition (reusable `load` functions or Svelte components) or if-statements to achieve what you want. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes! this is so important to mention and myself overlooked it too, groups are powerful and can have footguns if not handled correctly, but as always, use the right tool for the job. Should this be in a highlighted box? And it would be great to elaborate on the reusable layouts or conditionals inside a single layout to establish best practices. Maybe linking to an examples repo? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I enhanced the section with a little code example. For more a repository or an entry in the recipes section on |
Uh oh!
There was an error while loading. Please reload this page.