How to create vertical lines between headings

I’m trying to achieve vertical lines similar to this:

I have the following content structure as starting point inside a div…
Do note there are lots of headings and paragraphs and the line has to support at least five concurrent lines.

<h2>Title 1</h2>
<p>Some paragraph 1</p>
<p>Some paragraph 2</p>
<h2>Title 2</h2>
<p>Some paragraph 3</p>
<h3>Title 3</h3>
<p>Some paragraph 4</p>
<h2>Title 4</h2>

Options I’m trying and considered:

  1. adding borders to each p element, problem is how can I set five borders…
  2. convert them to a unordered list, which should make it easier to create lines, but it may collide with unordered lists inside the div that contains the content and may cause unexpected layout changes.
  3. some way to create lines with JS.

Hello there,

There are many ways to accomplish the look, but I find seeing what others have done helps a lot. For example, VSCode in the browser has the following structure:

<div>
  <div role="treeitem" data-index="0">
    <div>
      <div></div>
      <div></div>
      <div>
        <div>
          <div><span><a><span>.devcontainer</span></a></span></div>
        </div>
      </div>
    </div>
  </div>
  <div role="treeitem" data-index="1">
    <div>
      <div></div>
      <div></div>
      <div>
        <div>
          <div><span><a><span>.github</span></a></span></div>
        </div>
      </div>
    </div>
  </div>

  <div role="treeitem" data-index="18">
    <div>
      <div>
        <div class="indent-guide" style="width: 8px"></div>
        <div class="indent-guide" style="width: 8px"></div>
        <div class="indent-guide" style="width: 8px"></div>
        <div class="indent-guide" style="width: 8px"></div>
      </div>
      <div style="padding-left: 40px;"></div>
      <div>
        <div>
          <div><span><a><span>algorithm.tsx</span></a></span></div>
        </div>
      </div>
    </div>
  </div>
</div>

I removed a lot of attributes, and elements 2-17, but you can see how each element keeps track of its “index” (position), this way, you can indent the item the correct amount.

This is some of the CSS:

.indent-guide {
    display: inline-block;
    box-sizing: border-box;
    height: 100%;
    border-left: 1px solid rgba(88,88,88,0.4);
}
Full HTML
<div class="monaco-list-rows"
  style="transform: translate3d(0px, 0px, 0px); overflow: hidden; contain: strict; left: 0px; top: 0px; height: 2882px;">
  <div class="monaco-list-row" role="treeitem" data-index="0" data-last-element="false" data-parity="even"
    aria-setsize="51" aria-posinset="1" id="list_id_10_0" aria-selected="false" aria-label=".devcontainer"
    aria-level="1" draggable="true" style="top: 0px; height: 22px; line-height: 22px;" aria-expanded="false">
    <div class="monaco-tl-row">
      <div class="monaco-tl-indent" style="width: 0px;"></div>
      <div class="monaco-tl-twistie collapsible collapsed codicon codicon-tree-item-expanded"
        style="padding-left: 8px;"></div>
      <div class="monaco-tl-contents">
        <div
          class="monaco-icon-label folder-icon freecodecamp-name-dir-icon .devcontainer-name-folder-icon explorer-item"
          aria-label="/workspace/freeCodeCamp/.devcontainer" title="/workspace/freeCodeCamp/.devcontainer"
          style="display: flex;">
          <div class="monaco-icon-label-container"><span class="monaco-icon-name-container"><a class="label-name"><span
                  class="monaco-highlighted-label">.devcontainer</span></a></span></div>
        </div>
      </div>
    </div>
  </div>
  <div class="monaco-list-row" role="treeitem" data-index="1" data-last-element="false" data-parity="odd"
    aria-setsize="51" aria-posinset="2" id="list_id_10_1" aria-selected="false" aria-label=".github" aria-level="1"
    draggable="true" style="top: 22px; height: 22px; line-height: 22px;" aria-expanded="false">
    <div class="monaco-tl-row">
      <div class="monaco-tl-indent" style="width: 0px;"></div>
      <div class="monaco-tl-twistie collapsible collapsed codicon codicon-tree-item-expanded"
        style="padding-left: 8px;"></div>
      <div class="monaco-tl-contents">
        <div class="monaco-icon-label folder-icon freecodecamp-name-dir-icon .github-name-folder-icon explorer-item"
          aria-label="/workspace/freeCodeCamp/.github" title="/workspace/freeCodeCamp/.github" style="display: flex;">
          <div class="monaco-icon-label-container"><span class="monaco-icon-name-container"><a class="label-name"><span
                  class="monaco-highlighted-label">.github</span></a></span></div>
        </div>
      </div>
    </div>
  </div>

  <div class="monaco-list-row" role="treeitem" data-index="18" data-last-element="false" data-parity="even"
    aria-setsize="37" aria-posinset="1" id="list_id_10_18" aria-selected="false" aria-label="algorithm.tsx"
    aria-level="5" draggable="true" style="top: 396px; height: 22px; line-height: 22px;">
    <div class="monaco-tl-row">
      <div class="monaco-tl-indent" style="width: 32px;">
        <div class="indent-guide" style="width: 8px"></div>
        <div class="indent-guide" style="width: 8px"></div>
        <div class="indent-guide" style="width: 8px"></div>
        <div class="indent-guide" style="width: 8px"></div>
      </div>
      <div class="monaco-tl-twistie" style="padding-left: 40px;"></div>
      <div class="monaco-tl-contents">
        <div
          class="monaco-icon-label file-icon icons-name-dir-icon algorithm.tsx-name-file-icon name-file-icon tsx-ext-file-icon ext-file-icon typescriptreact-lang-file-icon explorer-item"
          aria-label="/workspace/freeCodeCamp/client/src/assets/icons/algorithm.tsx"
          title="/workspace/freeCodeCamp/client/src/assets/icons/algorithm.tsx" style="display: flex;">
          <div class="monaco-icon-label-container"><span class="monaco-icon-name-container"><a class="label-name"><span
                  class="monaco-highlighted-label">algorithm.tsx</span></a></span></div>
        </div>
      </div>
    </div>
  </div>
</div>

Hope this helps

2 Likes

Thank you!!
It definitively helps. Some question, if I pretend to insert with vanilla JS a div with position absolute before each content element, which would contain the divs with class
“indent-guide” and calculate the level of nesting based on previous heading tag (which I already do so that code would be ready) and insert according to that the number of divs with class “indent-guide” , what would you advice? and would it be too much of a performance problem to do so?

Ok doesn’t seem to be a performance problem :slight_smile:
I do have the following trouble. First context:

  1. I added similar to VSCode exmaple (thanks again!), a div that contains each content element. So that instead of:
<div>
<h3>title</h3>
<p>paragraph</p>
<p>...</p>
</div>

I have now:

<div class="main-div-indent-guide">
	<h3>title</h3>
</div>
<div class="main-div-indent-guide">
	<p>paragrph</p>
</div>

What I’m struggilng is how to detect that after a title it comes a paragraph, before it was simple just to check the nodename of next/previous elements, but with the divs the strucutre is dfferent… so far I have tried
current[counter].parentNode.nextElementSibling.childNodes[0].nodeName ; where “current” is the heading but I’m getting error that is null :confused:

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.