In CSS it is not possible for different elements of a page to "know" each other. The closest thing you can get is to use display flex and/or grid. This way the direct parent can control the way its children will display, kind of similar to React.
The main difference between flex and grid is that flex is 1 axis and grid 2 axis.
Working example using grid and flex:
<div class="container">
<div class="summary"><span class="text">Synonyms</span> <span class="icon">+</span></div>
<div class="details">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eveniet officiis sequi perspiciatis sapiente iure minus laudantium! Quidem iure consectetur quod odit iusto, labore sunt quae, enim nesciunt officiis, quia ad.</p>
</div>
<div class="summary"><span class="text">Concept</span> <span class="icon">+</span></div>
<div class="details">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eveniet officiis sequi perspiciatis sapiente iure minus laudantium! Quidem iure consectetur quod odit iusto, labore sunt quae, enim nesciunt officiis, quia ad.</p>
</div>
<div class="summary"><span class="text">Terms</span> <span class="icon">+</span></div>
<div class="details">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eveniet officiis sequi perspiciatis sapiente iure minus laudantium! Quidem iure consectetur quod odit iusto, labore sunt quae, enim nesciunt officiis, quia ad.</p>
</div>
</div>
<style>
.container {
display: grid;
/* summary's width needs to be relative to the longest text
and details needs to span the whole grid */
grid-template-columns: auto auto;
}
.summary {
grid-column: 1 / 2; /* start at the beginning of 1st column and end at the beginning of the 2nd column */
display: flex; /* create horizontal layout */
justify-content: space-between; /* place the available space between the children */
}
.details {
grid-column: 1 / 3; /* start at the beginning of 1st column and end at the end of the 2nd column */
}
</style>
As you can see, it is very readable and requires very little markup.
With flex and grid you need to think on 2 levels parent > child
. This means you need to change your React component accordingly:
const Expander = ({children, title, onExpandToggle, isExpanded}) => (
<>
<div class="summary" onClick={onExpandToggle}><span class="title">{title}</span> <span class="icon">+</span></div>
{isExpanded && (
<div class="details">
{children}
</div>
)}
</>
);
Here I removed the wrapper div
in order to use a Fragment
to ensure .summary
and .details
are direct children of a .container
. Note that I also moved the onClick on the whole title for UX reasons.
CSS Grid is very useful and flexible, it is worth learning it. The browser support is recent but quite good, just make sure you use autoprefixer.
You can also use tricks using display: inline-block;
whose size is based on its children but will involve workarounds when one of the children needs to overflow (like in your case). So I don't recommend it. I would also advise against using Javascript.
Don't hesitate to tell me what you think about this answer.