Wondering how could I display a separator at any position in JSX? For instance, I have the following list which displays text when clicking on the item:
The code is the following:
<Accordion>
{items.map((item, index) => (
<AccordionItem key={item.id} item={item} index={index} />
))}
</Accordion>
Having an object like this declaring the content of the list:
const items = [
{ label: "One", content: "lorem ipsum for more, see https://one.com" },
{ label: "Two", content: "lorem ipsum for more, see https://two.com" },
{
label: "Three",
content: "lorem ipsum for more, see https://three.com",
},
];
Now, I'd like to add a separator after the label "Two" to get something like this:
If we try the following way, I get active the element in index 0 and element in index2:
<Accordion>
{items.slice(0, 2).map((item, index) => (
<AccordionItem key={item.id} item={item} index={index} />
))}
<hr />
{items.slice(2).map((item, index) => (
<AccordionItem key={item.id} item={item} index={index} />
))}
</Accordion>
Then, getting this incorrect result:
Why it is happening this? Because my Accordion object is the following:
import { useState, createContext } from "react";
export const AccordionContext = createContext({
activeItemIndex: 0,
setActiveItemIndex: () => 0,
});
export const Accordion = (props) => {
const [activeItemIndex, setActiveItemIndex] = useState(0);
return (
<AccordionContext.Provider value={{ activeItemIndex, setActiveItemIndex }}>
<ul>{props.children}</ul>
</AccordionContext.Provider>
);
};
At the beginning activeItemIndex is 0, so when applying slice(2) the first element is also index 0 (however the element is at index 2).
How could I get the line right after the second element in the list?
Thanks a lot
You can conditionally render the separator based on the current index.
...
return (
<Accordion>
{items.map((item, index) => (
<React.Fragment key={item.id}>
<AccordionItem item={item} index={index} />
{index === 1 && <hr />}
</React.Fragment>
))}
</Accordion>
);
So if you see the above solution works for specific index i.e. 1
(means the second <AccordionItem />
). To make the separator position dynamic, you can pass a prop to the Accordion
component specifying the separator indices which you can then leverage to conditionally render the separator.
export const Accordion = ({ separators, children }) => {
const [activeItemIndex, setActiveItemIndex] = useState(0);
return (
<AccordionContext.Provider value={{ activeItemIndex, setActiveItemIndex }}>
<ul>{children(separators)}</ul>
</AccordionContext.Provider>
);
};
// To use
// const separatorIndices = [2]; // or any dynamic index which you want to provide.
const separatorIndex = 1; // or this whichever suits your needs
return (
<Accordion>
{items.map((item, index) => (
<React.Fragment key={item.id}>
<AccordionItem item={item} index={index} />
{/* {separatorIndices.includes(index) && <hr />} */}
{index === separatorIndex && <hr />}
</React.Fragment>
))}
</Accordion>
);