DEV Community

Cover image for Sphinx docs: How to activate tabs for your OS
Hugo van Kemenade
Hugo van Kemenade

Posted on

Sphinx docs: How to activate tabs for your OS

On the Python Developer's Guide and Pillow documentation we have some pages with tabs for different operating systems:

Screenshot showing instructions how to build Python. Some parts have Unix, macOS and Windows tabs. The macOS tab is active, showing a configure command to run in your terminal. Underneath is a second step with its own tabs and a macOS command. There's a macOS-specific note underneath.

It's possible to add some JavaScript so that the matching tab is activated based on the visitor's operating system.

Here's how!

Sphinx Inline Tabs

First add the Sphinx Inline Tabs extension to your docs' requirements.txt:

# requirements.txt
sphinx-inline-tabs>=2023.4.21
Enter fullscreen mode Exit fullscreen mode

JavaScript

Next, add activate_tab.js to your _static/ directory:

// activate_tab.js
// Based on https://stackoverflow.com/a/38241481/724176
function getOS() {
  const userAgent = window.navigator.userAgent,
    platform =
      window.navigator?.userAgentData?.platform || window.navigator.platform,
    macosPlatforms = ["macOS", "Macintosh", "MacIntel", "MacPPC", "Mac68K"],
    windowsPlatforms = ["Win32", "Win64", "Windows", "WinCE"],
    iosPlatforms = ["iPhone", "iPad", "iPod"];

  if (macosPlatforms.includes(platform)) {
    return "macOS";
  } else if (iosPlatforms.includes(platform)) {
    return "iOS";
  } else if (windowsPlatforms.includes(platform)) {
    return "Windows";
  } else if (/Android/.test(userAgent)) {
    return "Android";
  } else if (/Linux/.test(platform)) {
    return "Unix";
  }

  return "unknown";
}

function activateTab(tabName) {
  // Find all label elements containing the specified tab name
  const labels = document.querySelectorAll(".tab-label");

  labels.forEach((label) => {
    if (label.textContent.includes(tabName)) {
      // Find the associated input element using the 'for' attribute
      const tabInputId = label.getAttribute("for");
      const tabInput = document.getElementById(tabInputId);

      // Check if the input element exists before attempting to set the "checked" attribute
      if (tabInput) {
        // Activate the tab by setting its "checked" attribute to true
        tabInput.checked = true;
      }
    }
  });
}
Enter fullscreen mode Exit fullscreen mode

conf.py

Add the extension and JavaScript to your conf.py:

# conf.py
extensions = [
    "sphinx_inline_tabs",
]

html_js_files = [
    "activate_tab.js",
]
Enter fullscreen mode Exit fullscreen mode

reStructuredText

Almost there!

Add tabs to the reStructuredText files.

For example, here we have three different commands; one for Unix, one for macOS, and one for Windows:

.. tab:: Unix

    .. code-block:: shell

        ./python -m test -h

.. tab:: macOS

    .. code-block:: shell

        ./python.exe -m test -h

.. tab:: Windows

    .. code-block:: dosbatch

        .\python.bat -m test -h
Enter fullscreen mode Exit fullscreen mode

Finally, add the JavaScript to the same reST page to activate the correct tab:

.. raw:: html

    <script>
    document.addEventListener('DOMContentLoaded', function() {
      activateTab(getOS());
    });
    </script>
Enter fullscreen mode Exit fullscreen mode

You can see the results here. When the page loads, the browser finds the browser name, and activates the tabs with a matching name.

If you have many sets of tabs on a page, the corresponding OS tab will be activated for all. And if you click on another OS tab, all the others with the same name are activated.

Happy tabbing!


Header photo: "The Great Pyramid and the Sphinx" by National Galleries of Scotland, with no known copyright restrictions.

Top comments (2)

Collapse
 
astrojuanlu profile image
Juan Luis Cano Rodríguez

Thanks for sharing! Is there any Sphinx extension that takes care of the JS part automatically? So I don't have to copy-paste the code everywhere 😄

Collapse
 
hugovk profile image
Hugo van Kemenade

Good question, I was thinking of this too :)

Not that I know of, but this would make a good extension! It could be a suggestion for Sphinx Inline Tabs, or a new extension that depends on it.

One thing to note: you might want to be able to configure things differently depending on your use case.

For example, you might have a tab that says "Unix", or perhaps it says "Linux", and you want it to activate for Linux.

Or you have also tabs for building software targeting iOS or Android. But you don't want to activate when visiting with this devices, because you would still need to run those commands on a computer.

Compare the small differences between the devguide and Pillow:

But for a first version, it might be fine to come up with sensible defaults.