Best-practice for negotiating between parent and child components is using context
. For instance, here is an implementation for Tabs
and Tab
component: TabPanel
will be visible by clicking on related Tab
.
If we use nested Tabs
, higher level context values will be overwritten by the child Tabs
(context key is the same).
<!-- Tabs.svelte -->
<script context="module">
export const TABS = {};
</script>
And, to access to context:
<!-- TabPanel.svelte -->
<script>
import { getContext } from 'svelte';
import { TABS } from './Tabs.svelte';
const panel = {};
const { registerPanel, selectedPanel } = getContext(TABS);
registerPanel(panel);
</script>
{#if $selectedPanel === panel}
<slot></slot>
{/if}
In this REPL, if you click on the second tab inside the first root tabs, then click on the second/third tab of the root tabs, the selected tab for the child tabs will be changed.
How can we separate contexts in child components to avoid applying un-wanted changes?
This has nothing to do with the context. Contexts can be overridden in descendants without interfering with the parent context, it just hides that.
The problem is that the entire tab content gets destroyed when the tab is not visible and thus the selection is lost. If instead of using an {#if}
you just hide the content, the selection is retained (even without binding to some local state).
e.g.
<!-- In TabPanel.svelte -->
<div style:display={$selectedPanel === panel ? 'block' : 'none'}>
<slot></slot>
</div>