A couple of re-aligns ago on this website, my “biography” (a bit of text about myself) had some interactive controls on it. You could swap it between:
- Short, Medium, and Long
- First-Person and Third-Person
- Text, HTML, and Markdown
The big idea was to make it self-serve when someone asked me for this, say to accompany and interview or for an introduction at a conference. You never know what format they want it in, what the length limit is, or which tense. So I just did them all!
You’d think I would have done something clever to make that work, right?
I didn’t.
That’s why I don’t have it anymore. I created each possible permutation (3 Ă— 2 Ă— 3 = 18) separately, then just swapped between them depending on the combination of radio input values. Editing the bio was far too hard.
Couldn’t it be automated, though? The “which type of output” I always thought would be the easiest. So the other day I farted around with that and got this far:
I made it a Web Component named <bio-machine>, so it could be portable if needed. It’s not published anywhere except this Pen, so you can’t really just import and and use it, but maybe someday. It would need work.
The idea is that you only provide the Markdown, and the other formats are automatically created and the controls are added.
<bio-machine>
<div># Hello, World!
I'm Chris.</div>
</bio-machine>Code language: HTML, XML (xml)
All the rest of the code you see there is just setting up the Web Component.
I used a beta version of Tram-Lite. I like the idea that it requires no build step at all and the entire component is instantiated in a big block of HTML. I ultimately needed the help of Jesse Jurman, the creator of Tram-Lite, because the event binding stuff they built into v4 is just award with radio controls (apparently a generally weird problem).
Notes on the overall experience:
- I couldn’t just do
this.innerTextto grab all the text from the Light DOM. Notice the awkward<div>wrapper which allows forthis.querySelector("div").innerText. Feels like there should be a better way. - I don’t know that Tram-Lite lends itself well to packaging a component and letting people
importand use it from a CDN like many other Web Components. I like the HTML focus though. Is that what this kind of future syntax is about?import { MyComponent } from "./component.html" with { type: 'html' };I honestly don’t know. - I also couldn’t use
<script type="module">within Tram-Lite, so the other dependencies (the Markdown converter, the Syntax Highlighter, etc) had to be just global scripts, not imported. Again, I like the approach and philosophy of Tram-Lite, but it probably makes more sense to use Lit or something for this. I would have been more comfortable just attachingonChangehandles to all the radios anyway. - How would I approach allowing styles in? Certainly I could use
::partand whatnot to set the main background and text colors, but not with styling links, because you can’t make each link a part and that would be ridiculous anyway. And because you can’t do like::part(bio) abecause you can’t use the cascade, that’s off. So you’d have to send through a--link-colorcustom property or something, which is fine, but that’s potentially mix-and-matching styling approaches which feels silly. - I probably haven’t done the accessibility correctly here, in regards to the changing content. Should I do something like
<div role="region" aria-live="polite">for the bio area?
Nice article! Thanks for the shoutout and links to Tram-Lite, and more importantly, the feedback on Tram-Lite! Here’s some off-the-cuff thoughts:
In this case, it looks like you can do
this.textContent–textContenthas noted differences frominnerText(see https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#differences_from_innertext), but none of them directly reference slots or web-components. This may be noted in a spec, or a browser quirk, but given that there are known differences in how these are processed, I’m guessing this is something that is expected, and you could probably use going forwardYep, totally agree! It’s something I definitely want to improve, especially since the whole appeal of web-components is their portability. It’s the next big focus, most likely after the v4 release
Candidly, my experience with type=”module” is pretty limited, so this hadn’t stood out as a use-case before you brought it up. It’s not on the top of the list to support, but the fact that this behavior is inconsistent is something that’ll probably warrant future work (hopefully not another major version bump )
I haven’t played around with this too much, but potentially you could have a prop for styles (similar to react’s styled-components). Alternatively, since you are already using
oklch, you could have all the styles with a fixed lightness and chroma, and have thehuebe a prop that you pass into the component (defaulted to “220”, but dynamic for any other color scheme that you might want to fit into)Thanks again for playing around with this, it’s been super awesome to get other people’s detailed feedback here
Accessibility advice from Curtis Wilcox: