Tab control in Jekyll and Markdown?

I would like to create tabs, and want to show different contents by controlling the tabs below.

image

And I want to call the content by calling a include fragment when the tab is manipulated (See {% if …%} tag)

---

layout: archive

lang: en

ref: test

permalink: /docs/en/test/

tab_title1: Kinetic

tab_title2: Melodic

tab_title3: Foxy

product_group: test

sidebar:

  title: Test

  nav: "test"

---

{% if page.tab_title1 is "selected" %}

{% include en/platform/kinetic.md %}

{% elsif page.tab_title2 is "selected" %}

{% include en/platform/melodic.md %}

{% else %}

{% include en/platform/foxy.md %}

{% endif %} 

However, I have no idea how to call the include fragments when the tab is toggled as the tab_title1 is just Front Matter, but not HTML or JS.

below is my html codes,

{% if page.product_group==null and page.tab==null %}{% else %}

    <div id="tabs">

    <button id="{{ page.tab_title1 }}" class="tab" onClick="tab_handler(this)">{{ page.tab_title1 }}</button> <!-- on click시 default.html로 인자 전달후 함수 실행. -->

    <button id="{{ page.tab_title2 }}" class="tab" onClick="tab_handler(this)">{{ page.tab_title2 }}</button>

    <button id="{{ page.tab_title3 }}" class="tab" onClick="tab_handler(this)">{{ page.tab_title3 }}</button>

    </div>

    {% endif %}

below is the JS codes. I only made the toggle function.


    <script>
      function tab_handler(en){
        var tabs = document.getElementById('tabs').children;
        
        for(i = 0; i < tabs.length; i++) {
          tabs[i].className = "tab not__selected";
        }
        en.className = "tab selected";
      }
    </script>

My question is that,

If the {% include %} can include class=“tab” like the HTML, I can realize the tab control function.

is it possible to include “class” in the include fragments?

Yes you can add a class.

I don’t understand what you are trying to do but you can do this in includes.

<div id="tabs" class="tabs">

I think there is a simpler approach you can try which uses either markdown templates or JS to get tab behavior, rather than both.

See a navbar I added to my Jekyll site.

Here the result

The navbar is created in the includes file and uses pages that exist.
Each button points to a different markdown page.
So About button points to about.md which is /about.html for example.

Clicking on the button loads that page. This is a typical Jekyll approach.

If I wanted a tab to look different because it is selected, then I could add an if statement in the includes file which says use “selected” in the class if page.name equals to the item.name of the for loop. And then use CSS to make the button look different

I would recommend checking out Minima theme as well in this demo.

You can set your navbar using a custom value in your config or you can let the menu be created from a sorted list of pages.

If you would rather use the JS approach to avoid page loads, then I would do it like this all on one page.

<nav>
   <div id="btn-a" class="tab-selected">Tab A</div>
   <div id="btn-b">Tab B</div>
   <div id="btn-c">Tab C</div>
</nav>

<div id="content">

<div id="content-a" class="show">
  Text for first section 
</div>

<div id="content-b" class="hide">
  Text for second section 
</div>

<div id="content-c" class="hide">
  Text for third section 
</div>

</div>

To avoid setting selected and styling on your navbar you could even turn that into a radio selector since that is built into HTML and only one element is selected at a time. And you can use CSS to make your radio buttons more like traditional buttons or tabs.

Add JS to the navbar. Whenever there is a click on the entire nav element, then update the content.
For example when Tab B is clicked, you know the id is tab-b. So you set the class of all the content sections to be “hide” except the one with ID of content-b gets the class show instead.

And your CSS can have

.show {
 display: inline; // or block
}

.hide {
  display: none;
}

Also a reminder that Jekyll markdown or html is rendered at build time as static HTML. On a given page, jekyll will go through your if statement exactly once and find only one item selected and that will never change based on user input such as selecting things.

{% if page.tab_title1 is "selected" %}

{% include en/platform/kinetic.md %}

{% elsif page.tab_title2 is "selected" %}

{% include en/platform/melodic.md %}

{% else %}

{% include en/platform/foxy.md %}

{% endif %} 

A reason to use an if statement in a layout would be perhaps if the page frontmatter has a path to a logo image then you render that img tag otherwise you use a default logo. Or to make exactly one nav element look selected on each page, as in my first response.

If my HTML response I also made sure to render all the sections that could be shown, using user interaction on the tab button to determine which section is hidden or not. As JS can only show content that Jekyll put that as HTML.

I hope that helps you

1 Like

Hi MIchael,

Thank you for your help !
I’ve never known that the if statement only performs once when the page is loaded.

I think I should not use the if statement, but just manipulate the css display (none or block) :slight_smile:

Thank you again !!

You’re welcome.

To reiterate, Jekyll just outputs what becomes dump HTML to be served as static assets. On one of my sites, I build locally with Jekyll to create _site directory of images, html etc. And then use FTP to copy the site directory to a server. The server then serves the contents I sent it and it knows nothing of how to run liquid or Jekyll but that’s ok because there are no if statements or frontmatter in the html.

When using GH Pages and Netlify and other tools, the concept is the same. Code for Jekyll is separated from the build output. The difference is the site directory output built on GH Pages gets put someone internally on GH Pages so there is no FTP.

You might like to use the complete tab solution here for html, CSS and JS rather than the code I sent.

Or

Or with bootstrap

1 Like

I used the first article from w3schools - How to Create Tabs last week and it worked a treat.

I however wasn’t able to keep the text as markdown while using the tabs. I think either Jekyll or I had a trouble differentiating what was markdown and what was HTML. I rendered content from three XML files into formatted text which was output in each of three tabs.

the XML files required a few if and for statements and which the code I had written seemed to break some of the markdown rendering (probably my fault.) I got it sorted by just using HTML.

That’s great to hear.

It is possible to mix html and markdown but it can be impractical if you do things like classes.

This will render markdown as expected

<div class="foo">

- A
- B
- C `ls`

</div>

Note that the markdown must not be indented otherwise it will turn into code blocks. And there must be white space on either side to separate from the tag. Actually only the top whitespace matters but for readability I do both.

Or put a string literal or variable through a filter.

<div>{{ '[Text](target)' | markdownify }}</div>

@MichaelCurrin
@gavin-terpstra

Here is my way to add class to the markdown (Kramdown).

See below code.

#1 The code below only works when the parse option ({::options parse_block_html=“true” /}) is defined as true, so that the markdown inside the block level won’t be ruined.

{::options parse_block_html="true" /}

<div class="{{ page.tab_title1}}">

{% include en/platform/kinetic.md %}

</div>

#2 If you use capture and endcapture variable, you can wrap your markdown format with elements, and it will not ruin the markdown format.,

{% capture foxy_test %}

{% include en/platform/foxy.md %}

{% endcapture %}

<div class="foxy_test" ">{{ foxy_test | markdownify }}</div>

#3 You can add class to the one line string to the markdown format using {: .class_name}

This looks very simple, but only problem is that I can only add a class to one string. I don’t know the reason. I guess there is some way to wrap whole contents…


# Title (#title)
{: .class_name}

fdsafasfas

```

They all works great for me

I’m using this approach … as far as i can see is iterating on my pages at ‘/’ folder

yet, i’m wondering, how should it tweak it on order to adapt to my needs, travel agency use case:

  • Argentina
  • Bolivia
  • Brasil & Pantanal
  • Chile & Easter island
  • Colombia
  • Costa Rica
  • Cuba
    etc … defined as a jekyll ‘collection’ on its own folder ‘destinations’ .

image

and each destination offers several Itineraries to follow, say …

  • Bolivia
    ** itinerary1- B. roundtour
    ** itinerary2- Andes …
    etc.
    etc …

trying to figure out how to adapt :thinking:

May i iterate in a given - specific folder ?

Umh, like they do heremay i use ‘filters’ instead of ?

PS: oh… i see this approach might help too

Yeah when you iterate over site.pages, jekyll has no concept of directories.

But you can split a path of a page by / and count the pieces to get the depth. So you can find all pages at say level 2 down because they have the same depth.

And then you can find “child” pages by filtering to pages which have a common item.dir path as the current item’s tab.dir value.

My fractal project supports nesting of content dynamically. My layouts and includes files effectively allow a page to show only the pages directly below it. Then each page then shows its pages directly below it and so on.

There are also conversations on the forum here.

I would recommend you solve your problem using simple output like making bullet point output that looks a like a tree of all pages on a single page. Then you go a step further and turn that into tab structure on the page.

Oh… sure, i’ll put it to work in my project ,

Umh, i’m wondering… would it wokrk iterating upon collections too ?

@MichaelCurrin

Once more, ThX for the inspiration

1 Like