I'd like to ask someone who can figure out how to allow this accordion component to open only one section at a time.
It means that if a new accordion is open the previous one has to close automatically.
In the ideal situation, this function could be optional for specific accordions.
Thank you for your time.
Accordion.svelte
<script>
import { linear } from 'svelte/easing';
import { slide} from 'svelte/transition';
export let open = false;
function handleClick() {
open = !open
}
</script>
<div >
<div on:click={handleClick}>
<div >
<slot name="head"></slot>
</div>
</div>
{#if open}
<div transition:slide="{{duration: 500, easing: linear}}" >
<slot name="details">
</slot>
</div>
{/if}
</div>
<style>
div.accordion {
margin: 1rem 0;
}
div.header {
display:flex;
width:100%;
}
div.header .text {
flex: 1;
}
div.details {
background-color: transparent;
padding:1rem;
}
</style>
app.svelte
<script>
import Accordion from "./Accordion.svelte"
</script>
<Accordion>
<div slot="head">
<h2>Test one</h2>
</div>
<div slot="details">
<ul>
<Accordion>
<div slot="head">
<h4>The test of subitem?</h4>
</div>
<div slot="details">
<li>1</li>
<li>2</li>
<li>3</li>
</div>
</Accordion >
<Accordion>
<div slot="head">
<h4>Test of subitem 2</h4>
</div>
<div slot="details">
<li>one</li>
<li>two</li>
<li>three</li>
</div>
</Accordion>
</ul>
</div>
</Accordion>
<Accordion>
<div slot="head">
<h4>Second test</h4>
</div>
<div slot="details">
<ul>
<li>again one</li>
<li>two again</li>
<li>three repeat</li>
</ul>
</div>
</Accordion>
<style>
li {
margin: 0;
padding: 1em;
text-align: left;
list-style-type: none;
cursor: pointer;
color: black;
}
h4, h2 {
cursor: pointer;
}
</style>
CodePudding user response:
For this one would usually use a context. The context can then manage the current accordion (or a key representing it) or dispatch events to other accordion instances.
As an example of storing the current accordion:
import { setContext, getContext } from 'svelte';
import { writable } from 'svelte/store';
const key = {}; // Object instances are unique, hence useful for keys
export const getAccordionContext = () => getContext(key);
export const createAccordionContext = () => {
const current = writable(null);
const context = { current };
setContext(key, context);
return context;
}
If there is no wrapper component that is used in conjunction with the accordion items, a context has be created elsewhere (e.g. the App
). Also, each accordion item should also create its own context, so if it contains items of its own, it will not be closed if a child is opened.
When an accordion is opened the current accordion of the context can be updated. A reactive statement can be used to close all other accordions that belong to a context.
// In Accordion.svelte
const { current } = getAccordionContext();
const currentKey = {}; // Object representing current accordion component
createAccordionContext(); // Context for children
function handleClick() {
open = !open
if (open)
$current = currentKey;
}
$: if ($current != currentKey)
open = false;