Testing Code Tabs
This page displays how my Code Tabs plugin, jdvp-codetabs-commonmark, displays code blocks. See the linked project's README for installation instructions. This page will serve as a demo of the project's functionality since it can't be shown in the pure markdown README.
This project was largely spurred by my desire to include tabbed code switchers in my articles since I wanted to show examples in multiple languages - usually Java and Kotlin - in the same article in order to help the largest audience. I really liked the code tabs on the Android Developer site and they seemed to be the most aesthetically pleasing option that I had seen. An example from the android developer documentation can be seen in this documentation on manual dependency injection.
I didn't see anything that really matched what I was looking for so I decided to try building it myself. There was a lot I had to learn from css variables for theming to jekyll plugin hooks but that's a story for another time.
The main feature of this project is that it allows the addition of tabs to code blocks to concisely show multiple snippets of code. It also allows the ability to copy code blocks (which is opt-in on a per code block basis) and ability to switch between light and dark mode inside the code blocks. Switching between light and dark mode is currently always enabled but I want to make it a configuration option to allow either hard-coding or auto (user selection) mode.
Single code block
A single code block can be displayed without tabs. To do so, ensure the code block is isolated in markdown and doesn't have anything after the language directive.
```md
For example, this is a code block
```
Single code block with tab as labels
A single code block can use a tab as a label. To do this, include the desired text in the code fence after the language as shown in the example below.
```md Markdown Example For example, this is a code block ```
Copy-enabled code blocks
A copy button can be added to any code block (even those without tabs) by adding the string codeCopyEnabled
to the code fence. This string will be removed so will never be part of your label. Unfortunately, this means you can't have a label with that text! The icon appears on the upper right-hand corner as shown below.
```md Markdown Example codeCopyEnabled For example, this is a code block ```
Example without tabs:
```md codeCopyEnabled
For example, this is a code block
```
Advanced code copying (Added in v1.1.0)
If you want, you can also specify which lines you want to be able to copy. This is helpful in cases where you are providing documentation or output samples inline with the code but just want the user to copy an individual line
To copy a single line, you can specify the line number as the value for codeCopyEnabled
. This is 0-based. For example, if you wanted to copy the line at index 2 (i.e. the third line in the code block), you could do codeCopyEnabled="2"
To copy multiple lines in order, you can use -
to specify a range. For example to copy lines 1 through 3 you could do the following: codeCopyEnabled="1-3"
. Ranges should work whether you specify them forwards or backwards (1-3
and 3-1
should both work) but will always copy the lines in the order they appear in the code block.
You can also specify disjoint lines to be copied. To do this, use ,
. It can also be used in tandem with ranges. For example, codeCopyEnabled="1-3,7"
would copy lines 1 through 3 and line 7.
There are some safe-guards in place. I.e. if you choose a line number that doesn't exist in the code, it shouldn't break. However, I would urge you to be careful haha
If you don't specify any line numbers (as in the previous section), the entire block will be copied.
<!--- The next line is the header for this code block --> ```md Single Line codeCopyEnabled="2" Only the text on this line will be copied
<!--- The next line is the header for this code block --> ```md Single Line codeCopyEnabled="2" <!--- But maybe --> <!--- We have some extra comments we don't wanna copy --> This line will be copied And this one And this one too!
<!--- The next line is the header for this code block --> ```md Disjoint + Range codeCopyEnabled="2, 4, 6-8" This line will be copied <!--- This line not copied --> See, isn't this useful? <!--- Another non-copied line --> A B C is for Copied!
Multiple code tabs
To use multiple code tabs, just put code blocks next to each other in your markdown. If you create code tabs this, way you don't necessarily need to include custom names for each tab as above. If you don't include a name after the language in the code fence, it will just take the language name from the fence itself. In the example below "Kotlin" and "Markdown Example" are using custom tab names but "java" is not.
It's also worth noting that you can include a copy option on individual code blocks inside of a tabbed container without having to allow copying on all of them. In the example below, only the java section has a copy button (although a user could still select the text and copy/paste that way).
data class Example( val text: String )
class Example { String text; Example(String text) { this.text = text; } String getText() { return text; } }
```kotlin Kotlin data class Example( val text: String ) ``` ```java class Example { String text; Example(String text) { this.text = text; } String getText() { return text; } } ```
Multiple code tab components on a single page
If you have multiple code tab components on a single page, language selections on one can change another. There are some rules to this behavior:
- Selecting a tab on one component will switch all components to the language of that tab as specified by the code fence, not the custom label. For example, if you choose the java tab above, it will select the Java tab below (and vice versa) even though they have different user-visible labels.
- Components are allowed to have multiple tabs of the same language. In that case, when selecting the same language from a different code switcher, the first matching language will be switched to for other components.
data class Example( val text: String )
class Example { String text; Example(String text) { this.text = text; } String getText() { return text; } }
data class Example2( val text: String )
Code block with line numbers
At this time, this feature does NOT work with codeblocks with line numbers generated with the highlight liquid tag.
In case you don't know, liquid codeblocks look like this:
{% highlight kotlin linenos %}
data class Example(
val text: String
)
{% endhighlight %}
Sample showing current behavior:
1
2
3
data class Example {
val text: String
}
1
2
3
4
5
6
7
8
9
10
11
class Example {
String text;
Example(String text) {
this.text = text;
}
String getText() {
return text;
}
}
Other References
- I found this article really helpful about how to do theming with css, which I'd never done before: Dark Mode Revisited
- This plugin was the first place I looked for this functionality but wasn't what I wanted from a usage perspective since it requires using more liquid tags and also was using a pretty large UI library to achieve it's results. Still pretty cool though! jekyll-code-tabs
There are currently no comments on this article, be the first to add one below
Add a Comment
Note that I may remove comments for any reason, so try to be civil. If you are looking for a response to your comment, either leave your email address or check back on this page periodically.