A Code Block Web Component With Line Numbers, Wrap Toggles, Font Sizing And Copy Buttons
Introduction
My site is built from my notes. A lot of my notes have code samples. That means a lot of site code blocks.
I've never been happy with any of the formats I've used for blocks. There's always this tricky dance of trying to balance the font size to show enough of tabbed lines and the amount of wrapping that occurs overall. Any global setting that works well for some blocks sucks for others.
So, I made a web component to make each block customizable.
Here's what it looks like:
Some Details
You can grab the javascript and css for the component further below, but first a few notes about how things work:
-
The code block is made by wrapping a web component's custom element around a regular chunk of HTML. When the JavaScript for the component fires it adds the button functionality to the bottom of the block
-
The component is designed to work as a progressive enhancement. Specifically, if JavaScript is off or doesn't trigger properly the code block still shows up
-
The line numbers and syntax highlighting are done directly in the HTML and CSS from my site generator1 (i.e. they'll still work even if the JavaScript doesn't)
-
The height of the code block doesn't shrink if you reduce the font size or turn off wrapping. (This keeps the buttons in the same position unless you enlarge the font in which case they get pushed down if the area needs to grow)
Next Steps
There are a copule other things I want to add to the component:
-
Add the ability to start line numbering an arbitrary number
-
A flag to turn off the "Copy" button. This would be for times like when I'm pulling out a single line of code from a larger section and copying the code wouldn't really make sense without the rest of the context
-
A feature to collapse longer blocks of code. For example, I'm not really documenting the code blocks for the componet below. They're mainly there to copy and paste if you want to use them. So, there's no need to have them be their full lenght by default.
-
Only show the button to toggle wrapping if the content needs it. (I had an initial version of this working and like it, but it doesn't play nice with the way I'm handling the loading of my site with the visibility turned off to help minimize flashing when determining the color scheme to use)
-
Figure out a couple spacing issues with the height of the code block and the width of buttons that are marked by comments in the JavaScript. These also might have to do with the way I'm loading color scheme for my site, but I need to look into it more.
The Code
Here's another example of the output along with all the code necessary to produce it. You should pretty much be able to copy/paste the CSS and JavaScript and then have your site mimic the HTML tags and classes to get things to work.
(Note that the code on the page is live so I changed
the various names to add an -x
to prevent things
from conflicting with my production version. You can,
of course, change the names to anything that fits more
with your naming conventions.)
Output From HTML
Alfa
Bravo
Charlie is a long line that will wrap if your browser window is small enough. If you've got a big monitor and it hasn't wrapped yet, try making the browser window smaller...
Delta
A Basic Example
Alfa
Bravo
Charlie is a long line that will wrap if your browser window is small enough. If you've got a big monitor and it hasn't wrapped yet, try making the browser window smaller...
Delta
CSS
aws-code-block-x {
border-radius: 0.3rem;
border: 1px solid blue;
display: block;
margin-bottom: 2rem;
position: relative;
.aws-code-block-buttons-x {
text-align: right;
border-top: 1px solid blue;
}
.aws-code-block-buttons-x button {
padding-block: 0.3rem;
}
.aws-code-block-sidebar-x {
border-right: 1px solid blue;
}
.aws-code-block-marker-x{
counter-increment: codeBlockLineNumberX;
}
.aws-code-block-marker-x:before {
content: counter(codeBlockLineNumberX);
display: inline-block;
margin-left: -5ch;
padding-right: 2ch;
position: absolute;
text-align: end;
width: 5ch;
}
.aws-code-block-title-x {
text-align: center;
border-bottom: 1px solid blue;
}
.aws-code-block-wrapper-x {
counter-reset: codeBlockLineNumberX;
display: grid;
grid-template-columns: 5ch 1fr;
}
.aws-code-block-wrapper-x pre {
overflow-wrap: break-word;
padding-left: 1ch;
white-space: pre-wrap;
}
.aws-code-block-wrapper-x pre.no-wrapping {
white-space: pre;
overflow-wrap: normal;
overflow-x: auto;
overscroll-behavior-x: none;
}
}
JavaScript
Endnotes
-
I haven't really written up how all this works. I try to use good names in the code. Hopefully, they'll get the point across. If not, hit me up on mastodon.
-
This is my first real web component. I asked a lot of questions to a lot of folks to figure everything out. I'm still at the early part of the learning curve though. If you see something weird or scary that I should know about, I'm all ears.
-
As mentioned above, my site generator outputs all the HTML necessary to add the line numbers and syntax highlighting via CSS with needing JavaScript for the process. If you want to use something like prisma it'll take a little more work on your side.
Footnotes
- Neopoligen Website Builder
My web site engine that I've been building over the past few years.
References
-
The rust crate I'm using for syntax highlighting.
-
This is how I'm using the rust syntect create to generate the HTML with the empty spans for the line numbers.
-
This is the main post I used for reference when figuring out how to add line numbers in CSS. My approach is a little different in that I'm not wrapping the entire line. Instead, I'm using the single empty span at the start of each line.
-
-
-
-
-
-