Nested Lists in Rich Text Lists (bullets)

Title: A Solution for Creating Nested Lists in Rich-Text Fields with jQuery

Here’s a solution I recently discovered for creating nested lists in rich-text fields using jQuery.

The issue I faced was how to create sub-bullets in lists since Webflow’s rich-text editor does not directly support them. The goal was to take lists where list items marked with ~ or ~~ at the start of the text would be turned into sub-bullets.

After a lot of experimentation and tweaks, I came up with a jQuery script that does just that. Here’s a step-by-step guide on how to implement this solution:

Step 1:

We’re going to use ~ as an indicator for a sub-bullet and ~~ for a sub-sub-bullet in our list items.

For example, create your list like this:

<ol>
    <li>List Item 1</li>
    <li>~Sub List Item 1</li>
    <li>~~Sub Sub List Item 1</li>
    <li>List Item 2</li>
</ol>

Step 2:

Add the following jQuery code to your Webflow project. This script will process your lists on document ready:

<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
$(document).ready(function() {
    $('ol, ul').each(function() {
        let $list = $(this);
        let $items = $list.children('li');
        let stack = [$list];
        
        $items.each(function() {
            let $item = $(this);
            let text = $item.text();
            let level = text.startsWith('~') ? text.split('~').length - 1 : 0;
            
            if(level > 0) {
                text = text.replace(/^~+/g, '').trim();
                $item.text(text);
            }
            
            while(stack.length > level + 1) {
                stack.pop();
            }
            
            if(level >= stack.length) {
                let $newList = $('<ol>').addClass(level === 1 ? 'alphabetical' : 'roman');
                $newList.append($item.detach());
                let $parentLi = stack[stack.length - 1].children('li').last();
                if ($parentLi.length) {
                    $parentLi.append($newList);
                } else {
                    console.error('Expected a parent <li> but none was found. This might be due to incorrect nesting of "~"s.')
                }
                stack.push($newList);
            } else if (stack[level]) {
                stack[level].append($item.detach());
            } else {
                console.error('Unexpected condition: no stack[level] found. Please check your list structure.')
            }
        });
    });
});
</script>

Step 3:

Style your lists using CSS. You can use the class names alphabetical and roman which have been added to nested lists:

ol.alphabetical {
    list-style-type: lower-alpha; /* a., b., c., etc */
		margin: 0; /*optional*/
}

ol.roman {
    list-style-type: lower-roman; /* i., ii., iii., etc */
		margin: 0;/*optional*/
}

And That’s It!

The result should look like this:

<ol>
    <li>List Item 1
        <ol class="alphabetical">
            <li>Sub List Item 1
                <ol class="roman">
                    <li>Sub Sub List Item 1</li>
                </ol>
            </li>
        </ol>
    </li>
    <li>List Item 2</li>
</ol>

I hope this solution helps others who might face the same challenge. If you have any comments or improvements, please don’t hesitate to share!

2 Likes

@pixelsock This is the only solution I’ve seen to this nested list problem that is semantically legit… and accessibity compliant, more importantly. If I understand this correctly, you’re actually re-writing the HTML via your javascript so that what you end up with in your html matches what a user would expect to see on the screen. I haven’t tested this yet, but am hopeful this works as you are suggesting. One obvious improvement I might try to incorporate would be modifying the script to work with ordered and unordered lists (whereas if I’m not mistaken it currently only works for ordered lists… right?).

Update: Just tested in Webflow. Works like a charm on ordered lists, and it kind of works for unordered lists, too, although the html shows the use of the ‘ol’ element rather than ‘ul’. Not a huge deal, other than an accessibility issue. But pretty sure I can fix that script to resolve that. Love it, thank you for sharing!!

This is built into the SA5 nocode libs as well.
Works on both ordered and unordered lists, and handles skipped levels as well as prefixes for special use cases like pro and con lists.

1 Like