goediaz
goediaz

Reputation: 652

Provide data to main Layout from any route in SvelteKit

I have to following folder structure and I'm struggling to find the best way to provide my main layout with some props.

src/
└── routes/
    └── (app)/
        ├── route1/
        │   └── +page.svelte
        ├── route2/
        │   └── +page.svelte
        └── +layout.svelte 

To have more context, the main layout has a Sidebar menu component that needs a list of elements to render based on the selected route. So I need to find a way to communicate and change the props of one component in the main layout from any route.

I tried using slots and send the complete Sidebar as a slot for the main layout using a route layout but it didn't work. As far as I later understood, each layout can only have one main slot. I also tried to investigate if I can use a Global State somehow for this implementation but it feels way too complicated for what I'm trying to do.

Upvotes: 1

Views: 1126

Answers (3)

Kai Magnus
Kai Magnus

Reputation: 1

As of 2025, Svelte 5 and Kit 2.12, you can use page, from "$app/state" to do this.

In "route1/+page.js" return the data you want to display in your Sidebar component, for example:

export const load = (async () => {
    return {
        navItems: ["Home", "Profile", "Settings"],
    };
}) satisfies PageLoad;

Then in "(app)/+layout.svelte" access the data via:

import { page } from '$app/state';

<Sidenav items={page.data.navItems} ></Sidenav>

This works wherever you can add data to a page, such as +page.server.js, and the layout variants and as they state in the docs, you can import from $app/state directly in a component as well, because it is independent of your folder structure. The available data depends on the inheritance logic of the current route of course.

Upvotes: 0

Stephane Vanraes
Stephane Vanraes

Reputation: 16451

If you only have to provide data and don't need to change anything while on the page you can also opt for using the load function.

in /route1/+page.ts you would then have

export async function load() {
 return {
   sidebar: [1,2,3]
 }
}

and in the layout.svelte

{#each $page.data.sidebar ?? [] as item}
  <p>{item}</p>
{/each}

$page is a store that holds among other things all the data returned from the load functions, so it will automatically update when going from one page to another, you could also do this in a Sidebar.svelte component instead of the layout of course.

Upvotes: 5

brunnerh
brunnerh

Reputation: 185280

Would possibly use a context for that, set it in the layout and interact with it in the route. Put in a store to make data reactive or a function that acts like a callback. E.g.

let selectedItem;

setContext('nav-context', {
  setSelected(value) { selectedItem = value }
});

Upvotes: 1

Related Questions