New - unofficial - feature: TABS - Hide/Show multiple blocks horizontally

Hi Matthieu,

I understand you have things to doā€¦ So to make things easier I made an example website: https://adina2775.softr.app

In creating this example, I noticed the excess space is caused by the largest block AFTER a footer has been added. So it somehow has to do with this footer.

What e-mail address can I send the invitation to?

Sent by direct message.

Update: No large space or huge space seen during the test, everyhting works fine on my end.

Hi, Great work! Can you advise how I link the buttons to the actual blocks. Somehow, i have difficulties to figure this out. Could you provide an example? Also how do i make the content of the blocks variable based on the linked Record.

For example. I have a page with ā€œList with vertical cards and tagā€ block. These card link into detail pages where i created this tabs section. I have data pulling from airtable into these detail pages.

Thanks in advance

Important update

This is true for the tab feature as well as for any other custom code using javascript.

From now on, as blocks load faster than the footer code is being executed, all javascript codes should be inside the header custom code of the page level (same for app level by the way), unless a third party tool tells you to insert a code in the footer.

There might be some exceptions but as soon as you use window.addEventListener('block-loaded-BLOCKID', () => { in a code => header.
As soon as you use javascript that should be run on page load => header.

Otherwise the script might work 50 to 70% of the timeā€¦ Which is not ideal

2 Likes

Great job Matthieu!! Thatā€™s really helpful. Thank you so much!

I changed the blocked-loaded listener to: window.addEventListener('DOMContentLoaded', () => {
and seems to be behaving.

Great custom code, I have been using it a lot in one of my projects! Surprised it isnĀ“t a standard feature in Softr.

There is one thing that I have noticed that is behaving a bit weird when it comes to Calendar blocks. If the calendar block is connected to the first button, and therefore is displayed right away, everything works as itĀ“s supposed to. But if the calendar block is displayed first when pressing another button, the items in the calendar are ā€œminimizedā€ to ā€œX moreā€ as the block does when there is a lot of items on the same date, even though thereĀ“s only one item. Triggering for example a filter so the calendar reloads fixes it.

See images below before and after triggering a filter in the calendar block:

image
image

Hi,

I know exactly whatā€™s wrong, itā€™s specific to the calendar block.

Can you show your script for tabs (and tell me what is the calendar ID in this script) so I can quickly debug it?

Sure thing, thanks!
List3 (yes, I am lazy with the naming of blocks :grinning:) is the calendar block.

<!DOCTYPE html>
<html>
<head>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Inter&display=swap');
        
         .button-group {
            display: flex;
            justify-content: center;
        }

        .button {
            background-color: #4B664D;
            color: white;
            font-family: 'Inter', sans-serif;
            font-size: 15px; 
            padding: 10px 20px; 
            margin-right: 30px;
            padding-top: 8px;
            padding-bottom: 8px;
            border-radius: 14px;
            border: none;
            cursor: pointer;
        }
        
        .button:hover {
        background-color: #f5e507;
        color: #182939;
       }
        
        .button:focus {
        outline: none;
       }

        .button:active, .active {
            background-color: #f5e507;
            color: #182939;
            outline: none;
        }

        @media (max-width: 480px) {
            .button-group {
                display: flex;
                flex-direction: column;
                align-items: flex-start;
            }

            .button {
                display: none;
            }

            .dropdown {
                display: block;
                width: 100%;
                margin-top: 10px;
                padding: 10px 20px; 
                border-radius: 14px;
                border: none;
                background-color: #4B664D;
                color: white;
                font-family: 'Inter', sans-serif;
                font-size: 15px;
                cursor: pointer;
            }
        }

        @media (min-width: 481px) {
            .button-group {
                display: flex;
                justify-content: center;
            }

            .dropdown {
                display: none;
            }
        }
    </style>
</head>
<body>
    <div class="button-group">
        <button class="button active" onclick="runButton1Script()">Arbete kommande vecka</button>
        <button class="button" onclick="runButton2Script()">Fƶretagsinfo</button>
        <button class="button" onclick="runButton3Script()">Alla arbeten</button>
        <select class="dropdown" onchange="runDropdownScript(this.value)">
            <option value="button1">Arbete kommande vecka</option>
            <option value="button2">Fƶretagsinfo</option>
            <option value="button3">Alla arbeten</option>
        </select>
    </div>
    <script>
        const buttons = document.querySelectorAll('.button');
        buttons.forEach(button => {
            button.addEventListener('click', function() {
                buttons.forEach(b => b.classList.remove('active'));
                this.classList.add('active');
            });
        });

        function runDropdownScript(value) {
            switch(value) {
                case 'button1':
                    runButton1Script();
                    break;
                case 'button2':
                    runButton2Script();
                    break;
                case 'button3':
                    runButton3Script();
                    break;
                default:
                    break;
            }
        }
    </script>
</body>
</html>

<script>
    // hide blocks 
    window.addEventListener('DOMContentLoaded', (event) => {
        document.getElementById("list1").style.display = "block";
        document.getElementById("list2").style.display = "none";
        document.getElementById("list3").style.display = "none"
    });

    function runButton1Script() {
        document.getElementById("list1").style.display = "block";
        document.getElementById("list2").style.display = "none";
        document.getElementById("list3").style.display = "none";;
        console.log("Button 1 clicked"); 
    }

         function runButton2Script() {
        document.getElementById("list2").style.display = "block";
        document.getElementById("list1").style.display = "none";
        document.getElementById("list3").style.display = "none";
        console.log("Button 2 clicked");
    }
          function runButton3Script() {
        document.getElementById("list3").style.display = "block";
        document.getElementById("list1").style.display = "none";
        document.getElementById("list2").style.display = "none";
        console.log("Button 3 clicked");
    }

</script>
</html>```

Try this one, replace the last script by:
I added window.dispatchEvent(new CustomEvent('reload-block-list3')); , itā€™s mandatory for the calendar block when using the tabs feature.

<script>
    // hide blocks 
    window.addEventListener('DOMContentLoaded', (event) => {
        document.getElementById("list1").style.display = "block";
        document.getElementById("list2").style.display = "none";
        document.getElementById("list3").style.display = "none"
    });

    function runButton1Script() {
        document.getElementById("list1").style.display = "block";
        document.getElementById("list2").style.display = "none";
        document.getElementById("list3").style.display = "none";;
        console.log("Button 1 clicked"); 
    }

         function runButton2Script() {
        document.getElementById("list2").style.display = "block";
        document.getElementById("list1").style.display = "none";
        document.getElementById("list3").style.display = "none";
        console.log("Button 2 clicked");
    }
          function runButton3Script() {
        document.getElementById("list3").style.display = "block";
        document.getElementById("list1").style.display = "none";
        document.getElementById("list2").style.display = "none";
        window.dispatchEvent(new CustomEvent('reload-block-list3'));
        console.log("Button 3 clicked");
    }

</script>

Works great, thank you!

2 Likes

@matthieu_chateau Thanks for this solution, this works great on the calendar block, which we were having issues with as well.

Weā€™re seeing the same behavior on the open street map block but the reload event doesnā€™t seem to have any effect on that block type. Does it require a different syntax?

Code below and screenshot of the behavior also attached.

    <style>
@import url('https://fonts.googleapis.com/css2?family=Inter&display=swap');
         .button-group {
            display: flex;
            justify-content: center;
        }

        .button {
            font-family: 'Inter', sans-serif;
            font-size: 14px; 
            font-weight: 500;
            //border-radius: 0;
            border-top-left-radius: 10px;
            border-top-right-radius: 10px;
            border: none;
            cursor: pointer;
            background-color: white;
            color: #2F3133;
            outline: none;
            border: none;
            text-align: center;
            border-bottom: 2px solid #D4D4D4;
            border-left: 2px solid #D4D4D4;
            border-right: 2px solid #D4D4D4;
            border-top: 2px solid #D4D4D4;
            transition .3s;
            margin-right: 0em;
            margin-left: 0em;
            padding-right: 20px;
            padding-left: 20px;
            padding-bottom: 8px;
            padding-top: 8px;
            }

        .button:active, .active {
           font-size: 14px; 
            font-weight: bold;
            //border-radius: 0;
            border-top-left-radius: 10px;
            border-top-right-radius: 10px;
            border: none;
            cursor: pointer;
            background-color: transparent;
            color: #2F3133;
            outline: none;
            border: none;
            text-align: center;
            //border-bottom: 2px solid gray;
            border-left: 1px solid #C8C8C8;
            border-right: 1px solid #C8C8C8;
            border-top: 1px solid #C8C8C8;
            transition .3s;
            margin-right: 0em;
            margin-left: 0em;
            padding-right: 20px;
            padding-left: 20px;
            padding-bottom: 8px;
            padding-top: 8px;
                     
        }
        
        button:focus {outline:0;}
        
        button:hover
    </style>
    <div class="button-group">
        <button class="button active" onclick="runButton1Script()">Projects</button>
        <button class="button" onclick="runButton2Script()">Project Map</button>
        <button class="button" onclick="runButton6Script()">Projects by Company</button>
        <button class="button" onclick="runButton3Script()">Project Stats</button>
        <button class="button" onclick="runButton4Script()">Calendar View</button>
        <button class="button" onclick="runButton5Script()">Gantt View</button>
    </div>
     <script>
    const buttons = document.querySelectorAll('.button');
        buttons.forEach(button => {
        button.addEventListener('click', function() {
            buttons.forEach(b => b.classList.remove('active'));
            this.classList.add('active');
        });
    });
</script>

<script>
    // hide blocks
    window.addEventListener('DOMContentLoaded', (event) => {
        document.getElementById("block2").style.display = "block";
        document.getElementById("block1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("chart3").style.display = "none";
        document.getElementById("chart5").style.display = "none";
        document.getElementById("chart6").style.display = "none";
        document.getElementById("chart7").style.display = "none";
        document.getElementById("calendar1").style.display = "none";
        document.getElementById("gantt1").style.display = "none";
        document.getElementById("projects").style.display = "none";
    });
    
    function runButton1Script() {
        document.getElementById("block2").style.display = "block";
        document.getElementById("block1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("chart3").style.display = "none";
        document.getElementById("chart5").style.display = "none";
        document.getElementById("chart6").style.display = "none";
        document.getElementById("chart7").style.display = "none";
        document.getElementById("calendar1").style.display = "none";
        document.getElementById("gantt1").style.display = "none";
        document.getElementById("projects").style.display = "none";
        console.log("Button 1 clicked"); 
    }
    
    function runButton2Script() {
        window.dispatchEvent(new CustomEvent('reload-block-block1'));
        document.getElementById("block1").style.display = "block";
        document.getElementById("block2").style.display = "none";
        document.getElementById("chart1").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("chart3").style.display = "none";
        document.getElementById("chart5").style.display = "none";
        document.getElementById("chart6").style.display = "none";
        document.getElementById("chart7").style.display = "none";
        document.getElementById("calendar1").style.display = "none";
        document.getElementById("gantt1").style.display = "none";
        document.getElementById("projects").style.display = "none";
        console.log("Button 2 clicked"); 
    }
    
    function runButton3Script() {
        document.getElementById("chart1").style.display = "block";
        document.getElementById("chart2").style.display = "block";
        document.getElementById("chart3").style.display = "block";
        document.getElementById("chart5").style.display = "block";
        document.getElementById("chart6").style.display = "block";
        document.getElementById("chart7").style.display = "block";
        document.getElementById("block1").style.display = "none";
        document.getElementById("block2").style.display = "none";
        document.getElementById("calendar1").style.display = "none";
        document.getElementById("gantt1").style.display = "none";
        document.getElementById("projects").style.display = "none";
        console.log("Button 3 clicked"); 
    }
    
    function runButton4Script() {
        window.dispatchEvent(new CustomEvent('reload-block-calendar1'));
        document.getElementById("calendar1").style.display = "block";
        document.getElementById("chart1").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("chart3").style.display = "none";
        document.getElementById("chart5").style.display = "none";
        document.getElementById("chart6").style.display = "none";
        document.getElementById("block1").style.display = "none";
        document.getElementById("block2").style.display = "none";
        document.getElementById("chart7").style.display = "none";
        document.getElementById("gantt1").style.display = "none";
        document.getElementById("projects").style.display = "none";
        console.log("Button 4 clicked"); 
    }
    
    function runButton5Script() {
        document.getElementById("gantt1").style.display = "block";
        document.getElementById("calendar1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("chart3").style.display = "none";
        document.getElementById("chart5").style.display = "none";
        document.getElementById("chart6").style.display = "none";
        document.getElementById("block1").style.display = "none";
        document.getElementById("block2").style.display = "none";
        document.getElementById("chart7").style.display = "none";
        document.getElementById("projects").style.display = "none";
        console.log("Button 5 clicked"); 
    }
    
    function runButton6Script() {
        document.getElementById("projects").style.display = "block";
        document.getElementById("gantt1").style.display = "none";
        document.getElementById("calendar1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("chart3").style.display = "none";
        document.getElementById("chart5").style.display = "none";
        document.getElementById("chart6").style.display = "none";
        document.getElementById("block1").style.display = "none";
        document.getElementById("block2").style.display = "none";
        document.getElementById("chart7").style.display = "none";
        console.log("Button 6 clicked"); 
    }
</script>

We only see the issue when the open street map block is not visible by default (or ā€œtabā€ 1).

If you swap your maps so that the open street map is the second option and not shown by default, thatā€™s the scenario where we run into it.

Indeed => visual bug!

Good to know that with google maps itā€™s all right.

No idea what can cause this

Thanks for confirming my sanity :upside_down_face:

Iā€™ll open a bug report on it.

Hi @matthieu_chateau, Thanks for this thread and insights!
Are all the hidden list-blocks loaded on page load?
I have a use case where I have about 5-10 list blocks on one page, but I only want to show one at a time. Ive noticed the more list-blocks I add and the more content they are supposed to display the slower Softr gets or even fails to load some or all blocks.
Here is my current setup: https://www.climesumer.com/actionhub (need an account to show items)

Is that true, and if yes, any idea how to work around that?

I highly appreciate your input. - Thanks

Hi Simon,

Blocks are hidden. Which means they are loaded - but hidden.

There is no way right now not to load a block with just javascript.

This might be implemented later by Softr.

That being said, careful => all your scripts related to this tabulation feature need to be in the header now (not the footer anymore).

1 Like

Hey @matthieu_chateau have you gotten any reports of users not having their edit buttons work on pages where they use the custom code for tabs? My edit modals have stopped popping up randomly and Iā€™m just wondering if it could be related to the cx code ā€¦Really praying it isnā€™t that though lol :frowning: I do not have time to rebuild all these dang pages haha but I know that was the risk

Hey @danyalamriben,

I havenā€™t seen any issues with this yet and I have a LOT of pages using custom tabs.

Maybe something else in your custom code is causing it?

Hi Diana,

I donā€™t have this problem though be careful => Custom code in the header sections