Code design: anchoring sidebar components

I am working on building a site for a “virtual comic book” in react. For context, I’m very new to web dev (I just finished working through Kirupa’s react book), so the entire website is just various instances of the div component stacked inside one another. Lucky for me, I think that gets me most of the way there!

The layout is simple. There is a column of dialogue where the main action happens story-wise. Then, there might be some interesting tangents that we want to include that don’t quite fit in the main storyline. So we want to include them as “extras” in the sidebar. We want them to line up with the line of dialogue that they correspond to. See the picture below to see what I mean.

One design constraint is that I don’t want to hardcode chapters and chapters of this. So right now, we have static JSON files that specify dialogue text, the associated images, and the “extras” that go with each line. Then we render the JSON into a page at runtime. This is probably not the most efficient way to deal with this problem, but as I said, I’m new to this.

Here’s a picture of the layout I want and the problems I’m running into.

As you can see, originally I had a lengthwise div component for each dialogue line, and it’s “extra” if it has one. That worked, but if the extra was very long, it would cause huge gaps in the dialogue. This completely defeats the purpose: the extra was supposed to be unobtrusive and optional to read.

I would like to have a design like the second one in the picture, but this is where React’s top to bottom design is killing me. I can figure out how to anchor an extra at a predetermined y-value. However, the y-value that each extra should be anchored at depends on the y-value that it’s dialogue line renders at.

Here’s what I tried: I get the y-value of each dialogue line when it renders. Then, I passed each dialogue line component a function from it’s parent, and when you call the function, it tells the parent what the child’s y-value is. Passing this up two levels, I can then collate this list of y-values with the extras that I should render. I then pass this list to the extras bar component, and it renders each extra at the correct height.

There are multiple problems with this approach. The first one is that I originally had some issues where I was setting the state of the parent components. Every time I set the state of the parent components, everything got re-rendered and I created infinite rendering loops that naturally crashed my page. Once I fixed that (I think) I still wasn’t getting stuff at the right y-values, because I think I was checking the y-values too early. I was checking them at componentDidMount(), but things move after that I think.

Also, with the level of skullduggery I have managed for implementing something that seems so simple, I don’t think I am using React as god intended.

There must be a better way! I would appreciate any advice on how to design my components better to get this to work! Thanks in advance!

Hi @vayu251 - welcome to the forums and thanks for writing this really awesomely detailed question :partying_face:

For what you are trying to do, there may be an easy solution here. It could just be as simple as using a CSS grid and segmenting your content across two columns as follows:

It is hard to know for sure if this can work without seeing an example. Can you post a version of your project online where I can easily check in the browser where the one “extra component” and a series of “dialogue” components are visible?


Thank you so much for your extremely prompt response! Here is my extremely un-prompt reply :sweat_smile:

You can see the components that are supposed to render in the extras bar here:

All of the other components (and some documentation) can be found from this root folder:

(There’s even a higher level folder in the repo, but it has some other random stuff.)

I appreciate any feedback or tips, even if it means restructuring a lot of stuff. Part of the point of the project for me is to learn react.


Hi, I just wanted to say that using the css grid solved the problem completely! Thanks for the tip :slight_smile: