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

Thank you very much! Is working perfectly. I would like to know, is there any way to change the position of the buttons on the header? Because when i choose the vertical orientation, the buttons end up on the buttom side…

Thanks again.

Nope

I hadn’t used it until now, but this piece of code is outstanding! Thanks @matthieu_chateau :sunflower:

Dear everybody,

This option with tab-view is amazing, it decluttered my website and makes it look so much more elegant. However, I have a minor issue - hopefully one of you knows how to resolve this:

I have a huge amount of padding on the bottom of each page (no matter which tab I am on, they all have the same excess padding). This is only visible in the browser (MS Edge), not in the Softr edit view → is there a way to remove this?


Strange, Does it do it without the tabs feature? like if the blocks were displayed all at once?
It shouldn’t be linked to the script but worth asking.

Did you check it on Chrome or another browser?

Hi Matthieu,

When the block is disabled, the excess padding is fixed (both in Edge and another browser DuckDuckGo). Also, note that this issue is specific to one page - all other pages where I use this tab-function don’t have this issue (the custom code is all the same - as you provided it).

I also did some trial and error with the specific block that seems to be causing this: removing all padding or limiting max items shown reduced to 3 - it doensn’t resolve the issue.

The blocks I use have a different background colors, from which I discovered that it is always (the background color of) the last block (before the footer-block).

Anything else I can try?

Here is a copy of the code I use:

@import url('https://fonts.googleapis.com/css2?family=Inter&display=swap'); .button-group { display: flex; justify-content: center; }
    .button {
        background-color: #000000;
        color: white;
        font-family: 'Inter', sans-serif;
        font-size: 16px; 
        padding: 10px 20px; 
        margin-right: 30px;
        padding-top: 9px;
        padding-bottom: 9px;
        border-radius: 7px;
        border: none;
        cursor: pointer;
    }

    .button:active, .active {
        background-color: #DBC6BA;
        color: #000000;
        outline: none;
    }
</style>
Keuzemogelijkheden Ontwerp opties buiten keuzeprofiel Gekozen ontwerp opties

This is a bug, I can’t help for this => customer service

Is there any way to jump directly to one of the tabs via the URL, just like I would usually add a #ID to the URL to scroll to a section? :slight_smile:

Yes, a code example would be:

<script>
  function getURLParameter(name) {
    const urlParams = new URLSearchParams(window.location.search);
    return urlParams.get(name);
  }

  window.addEventListener('DOMContentLoaded', (event) => {
    document.getElementById("table1").style.display = "block";
    document.getElementById("form1").style.display = "none";
    document.getElementById("chart1").style.display = "none";
    
    const tabParam = getURLParameter('tab');
    if (tabParam) {
      if (tabParam === 'table') {
        document.getElementById("table1").style.display = "block";
        document.getElementById("form1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
      } else if (tabParam === 'form') {
        document.getElementById("form1").style.display = "block";
        document.getElementById("table1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
      } else if (tabParam === 'chart') {
        document.getElementById("chart1").style.display = "block";
        document.getElementById("form1").style.display = "none";
        document.getElementById("table1").style.display = "none";
      }
    }
  });

  window.addEventListener('block-loaded-cta3', () => {
    console.log('CTA Block loaded');

    const buttonClickHandler = (e) => {
      const button = e.target.closest('#cta3 a[data-element="button"]:nth-child(1)');
      if (button) {
        e.preventDefault();
        document.getElementById("table1").style.display = "block";
        document.getElementById("form1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
        history.pushState(null, null, '?tab=table');
      }
      const button2 = e.target.closest('#cta3 a[data-element="button"]:nth-child(2)');
      if (button2) {
        e.preventDefault();
        document.getElementById("form1").style.display = "block";
        document.getElementById("table1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
        history.pushState(null, null, '?tab=form');
      }
      const button3 = e.target.closest('#cta3 a[data-element="button"]:nth-child(3)');
      if (button3) {
        e.preventDefault();
        document.getElementById("chart1").style.display = "block";
        document.getElementById("form1").style.display = "none";
        document.getElementById("table1").style.display = "none";
        history.pushState(null, null, '?tab=chart');
      }
    };

    document.body.addEventListener('click', buttonClickHandler);
  });
</script>

Here there is a CTA block with 3 buttons and 3 tabs.
Each time you will add ?tab=chart or ?tab=form or ?tab=table at the end of the url => it will display the right tab on page load

2 Likes

This is amazing!! Thank you!!!

Also, if you need to preserve a recordId while using this code (like https: //whatever. com/whateverpage?recordId=recxxxxx?tab=form)

<script>
  function getURLParameter(name) {
    const urlParams = new URLSearchParams(window.location.search);
    return urlParams.get(name);
  }

  window.addEventListener('DOMContentLoaded', (event) => {
    document.getElementById("table1").style.display = "block";
    document.getElementById("form1").style.display = "none";
    document.getElementById("chart1").style.display = "none";

    const tabParam = getURLParameter('tab');
    if (tabParam) {
      if (tabParam === 'table') {
        document.getElementById("table1").style.display = "block";
        document.getElementById("form1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
      } else if (tabParam === 'form') {
        document.getElementById("form1").style.display = "block";
        document.getElementById("table1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
      } else if (tabParam === 'chart') {
        document.getElementById("chart1").style.display = "block";
        document.getElementById("form1").style.display = "none";
        document.getElementById("table1").style.display = "none";
      }
    }
  });

  window.addEventListener('block-loaded-cta3', () => {
    console.log('CTA Block loaded');

    const buttonClickHandler = (e) => {
      const button = e.target.closest('#cta3 a[data-element="button"]:nth-child(1)');
      if (button) {
        e.preventDefault();
        document.getElementById("table1").style.display = "block";
        document.getElementById("form1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
        const recordIdParam = getURLParameter('recordId');
        if (recordIdParam) {
          history.pushState(null, null, `?recordId=${recordIdParam}&tab=chart`);
        } else {
          history.pushState(null, null, '?tab=chart');
        }
      }
      const button2 = e.target.closest('#cta3 a[data-element="button"]:nth-child(2)');
      if (button2) {
        e.preventDefault();
        document.getElementById("form1").style.display = "block";
        document.getElementById("table1").style.display = "none";
        document.getElementById("chart1").style.display = "none";
        const recordIdParam = getURLParameter('recordId');
        if (recordIdParam) {
          history.pushState(null, null, `?recordId=${recordIdParam}&tab=form`);
        } else {
          history.pushState(null, null, '?tab=form');
        }
      }
      const button3 = e.target.closest('#cta3 a[data-element="button"]:nth-child(3)');
      if (button3) {
        e.preventDefault();
        document.getElementById("chart1").style.display = "block";
        document.getElementById("form1").style.display = "none";
        document.getElementById("table1").style.display = "none";
        const recordIdParam = getURLParameter('recordId');
        if (recordIdParam) {
          history.pushState(null, null, `?recordId=${recordIdParam}&tab=chart`);
        } else {
          history.pushState(null, null, '?tab=chart');
        }
      }
    };

    document.body.addEventListener('click', buttonClickHandler);
  });
</script>

1 Like

I just take that code and insert it in the previous code to replace the part covered in script tags, right?

You will need to adapt it with the right cta ids and block ids. Just test it. It is supposed to replace the whole script yes.

I updated the blcok IDs, but not sure what the CTA IDs are? :slight_smile: the “cta3”? That’s my code:

<!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: #2B5472;
            color: white;
            font-family: 'Inter', sans-serif;
            font-size: 22px; 
            padding: 10px 20px; 
            margin-right: 30px;
            padding-top: 8px;
            padding-bottom: 8px;
            border-radius: 14px;
            border: none;
            cursor: pointer;
        }
        
        .button:hover {
        background-color: #CFE6D0;
        color: #ffffff;
       }
        
        .button:focus {
        outline: none;
       }

        .button:active, .active {
            background-color: #36B37E;
            color: #ffffff;
            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: 14px 16px; 
                border-radius: 12px;
                border: none;
                background-color: #36B37E;
                color: white;
                font-family: 'Inter', sans-serif;
                font-size: 18px;
                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()">All Jobs</button>
        <button class="button" onclick="runButton2Script()">Matching Jobs</button>
        <button class="button" onclick="runButton3Script()">My Applications</button>
        <button class="button" onclick="runButton4Script()">Sent Applications</button>
        <select class="dropdown" onchange="runDropdownScript(this.value)">
            <option value="button1">All Jobs</option>
            <option value="button2">Matching Jobs</option>
            <option value="button3">My Applications</option>
            <option value="button4">Sent Applications</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;
                case 'button4':
                    runButton4Script();
                    break;
                default:
                    break;
            }
        }
    </script>
</body>
</html>

<script>
  function getURLParameter(name) {
    const urlParams = new URLSearchParams(window.location.search);
    return urlParams.get(name);
  }

  window.addEventListener('DOMContentLoaded', (event) => {
    document.getElementById("table2").style.display = "block";
    document.getElementById("form2").style.display = "none";
    document.getElementById("chart2").style.display = "none";
    document.getElementById("list2").style.display = "none";
    
    const tabParam = getURLParameter('tab');
    if (tabParam) {
      if (tabParam === 'table') {
        document.getElementById("table2").style.display = "block";
        document.getElementById("form2").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("list2").style.display = "none";
      } else if (tabParam === 'form') {
        document.getElementById("form2").style.display = "block";
        document.getElementById("table2").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("list2").style.display = "none";
      } else if (tabParam === 'chart') {
        document.getElementById("chart2").style.display = "block";
        document.getElementById("form2").style.display = "none";
        document.getElementById("table2").style.display = "none";
        document.getElementById("list2").style.display = "none";
      } else if (tabParam === 'list') {
        document.getElementById("list2").style.display = "block";
        document.getElementById("form2").style.display = "none";
        document.getElementById("table2").style.display = "none";
        document.getElementById("chart2").style.display = "none";
      }
    }
  });

  window.addEventListener('block-loaded-cta3', () => {
    console.log('CTA Block loaded');

    const buttonClickHandler = (e) => {
      const button = e.target.closest('#cta3 a[data-element="button"]:nth-child(1)');
      if (button) {
        e.preventDefault();
        document.getElementById("table2").style.display = "block";
        document.getElementById("form2").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("list2").style.display = "none";
        history.pushState(null, null, '?tab=table');
      }
      const button2 = e.target.closest('#cta3 a[data-element="button"]:nth-child(2)');
      if (button2) {
        e.preventDefault();
        document.getElementById("form2").style.display = "block";
        document.getElementById("table2").style.display = "none";
        document.getElementById("chart2").style.display = "none";
        document.getElementById("list2").style.display = "none";
        history.pushState(null, null, '?tab=form');
      }
      const button3 = e.target.closest('#cta3 a[data-element="button"]:nth-child(3)');
      if (button3) {
        e.preventDefault();
        document.getElementById("chart2").style.display = "block";
        document.getElementById("form2").style.display = "none";
        document.getElementById("table2").style.display = "none";
        document.getElementById("list2").style.display = "none";
        history.pushState(null, null, '?tab=chart');
      }
       const button4 = e.target.closest('#cta3 a[data-element="button"]:nth-child(4)');
      if (button4) {
        e.preventDefault();
        document.getElementById("chart2").style.display = "none";
        document.getElementById("form2").style.display = "none";
        document.getElementById("table2").style.display = "none";
        document.getElementById("list2").style.display = "block";
        history.pushState(null, null, '?tab=list');
    };

    document.body.addEventListener('click', buttonClickHandler);
  });
</script>```

cta3 or #cta3 is the id of the CTA block for my example, yes

1 Like

Some people have noticed that when we use this code in a sliding modal, and I use softr CTAs with the “scroll to section” function, it redirects to a new tab and not in the modal.

I have the impression that it doesn’t work… Is it a softr bug because the scroll to section doesn’t work? I imagine it’s correctable with hardcoded buttons

It works for me (test it by clicking “open lateral” button for Project A here => https://test-play.softr.app/#list2)
Are you sure the scroll to section points to the page itself?

Thanks Matthieu, I’ll look into it, it’s really weird!

Hi Matthieu and others,

As my custom-code skills have progressed a little bit, I’d still hope an answer can be found to have this plague of excess white space addressed:

Preference 1: have the excess white space removed in its entirety → @matthieu_chateau does the screen print with details of this white space help you understand what it is and if it can be removed?

Preference 2: be able to color the background in line with the rest of the website → @matthieu_chateau do you know how I can address this piece of the website (I don’t see any ID) / what custom code addresses its background coloring?

This is what I have tried so far, but without any luck:

#div.content section {background: rgb(249,249,255);
background: radial-gradient(circle, rgba(249,249,255,1) 0%, rgba(255,255,255,1) 100%);}

#div.content {background: rgb(249,249,255);
background: radial-gradient(circle, rgba(249,249,255,1) 0%, rgba(255,255,255,1) 100%);}

#div.content section {background: rgb(249,249,255);
background: radial-gradient(circle, rgba(249,249,255,1) 0%, rgba(255,255,255,1) 100%);}

#extra-div section {background: rgb(249,249,255);
background: radial-gradient(circle, rgba(249,249,255,1) 0%, rgba(255,255,255,1) 100%);}

#div.extra-div section {background: rgb(249,249,255);
background: radial-gradient(circle, rgba(249,249,255,1) 0%, rgba(255,255,255,1) 100%);}

Details of this white space

element: <div class="extra-div" style="background: rgb(255, 255, 255); height: 235px; width: 100%;"></div>
selector: body > div.content > div.extra-div>
full XPath: /html/body/div[2]/div[33]

From the screen print it looks like it’s part of block “klaar3”, but if I disable that block, this line sticks to the previous block.

Hi @thijs

I have no idea what it is without seeing the full page in the Softr studio and all custom codes applied to this page as I never had this behaviour.

Update: I found that this is related to <!-- Stick footer to the bottom if the App is shorter than the viewport --> script. Which is made by Softr => untouchable.

There must be a reason why you have such a behaviour while the script is supposed to work without doing this. And the reason can’t be found just by screenshots, impossible to debug without having everything in hands, it doesn’t work like this.

You can ask one of the Softr customer service people to check in your app or give me an access to it (I won’t stay more than 15 min on it => I have work to do and Christmas is coming)