Getting your hands dirty and feet wet with Open Web Component Recommendations...sort of.
This a cross-post of a Feb 26, 2019 article from Medium that takes advantage of my recent decision to use Grammarly in my writing (so, small edits have been made here and there), thanks for looking again if you saw it there 🙇🏽‍♂️ and if this is your first time reading, welcome!
Welcome to “Not Another To-Do App”, an overly lengthy review of making one of the smallest applications every developer ends up writing at some point or another. If you’re here to read up on a specific technique to writing apps or have made your way from a previous installation, then likely you are in the right place and should read on! If not, it’s possible you want to start from the beginning so you too can know all of our characters’ backstories...
If you’ve made it this far, why quit now?
Make it a Reusable Part
When working with a specific component model it’s easy to get tricked into thinking that every piece of UI that you want to reuse should be structured in the form of that component model. In my application I chose to work with the component model native to the web, the web component, but what about when I don’t need/want to be encapsulating things within the shadow DOM, or when there isn’t state specifically related to the DOM in question to be managed over the lifecycle of the component/application? In these cases, I turn to lit-html
and its functional approach to template creation.
const reusablePart = () => html`... Your reusable part here ...`;
There are innumerable contexts where this pattern is valuable in the development of an application. We’ve actually already seen it, possibly without knowing it, when correcting the .map
linting error in a previous installment I moved the template part to /src/to-do-ui.js
which simultaneously takes advantage of this pattern while allowing for the code to be reused in the testing process:
import { html } from 'lit-element';
export const renderTodo = todo => html`
<to-do .todo="${todo}">${todo.todo}</to-do>
`;
export const renderTodos = todos => todos.map(renderTodo);
Here we see our list of to-dos (renderTodos
) being made by mapping the todos
array across the renderTodo
template. The renderTodo
template is then leveraged in the testing process to easily create the to-do
fixture we run out tests against.
import { renderTodo } from '../src/to-do-ui';
// ...
const newToDo = {
id: 2,
todo: 'New To Do'
};
it('is a to do', async () => {
const el = await fixture(renderTodo(newToDo));
expect(el.textContent).to.equal(newToDo.todo);
expect(el.todoId).to.equal(newToDo.id);
});
#winning
One of my favorite applications of this technique is for injecting SVG icons into my templates. ${iconPlus}
and you’re done! It’s so useful and presents such an interesting array of usability, a11y, and code reusability questions that I’m investigating ways that groups of tagged template literal based icons could be shared not just cross-project, but also cross framework via feather-icon-literals
. However, I’ll leave getting deeper into that for another day. In the case of my To-Do app, there’s just two icons; iconPlus
and iconMinus
. Both came out roughly like the following:
export const iconPlus = html`
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<line x1="12" y1="5" x2="12" y2="19" />
<line x1="5" y1="12" x2="19" y2="12" />
</svg>
`;
This is absolutely the most minimal implementation of this technique; every attribute is fixed, a11y is rented from the button the icon is in rather than applied to the icon, etc. From there, there are a number of other customizations that could be added, and now, if you make them, they’re centralized in one place for reuse across your entire project. Or, go the extra mile, break this out into its own package (or use mine, PRs welcome) and make it a dependency of as many projects as you’d like.
The Short Game
As voted on by a plurality of people with opinions on such topics that are both forced to see my tweets in their Twitter feed and had a free minute this last week, a 9000+ word article is a no, no.
So, it is with the deepest reverence to you my dear reader that I’ve broken the upcoming conversations into a measly ten sections. Congratulations, you’re nearing the end of the first! If you’ve enjoyed yourself so far, or are one of those people that give a new sitcom a couple of episodes to hit its stride, here’s a list of the others for you to put on your Netflix queue:
- Not Another To-Do App (Maybe now I can just use these reusable parts and never write another To-Do app again...)
- Getting Started
- Test Early, Test Often
- Measure Twice, Lint Once
- Make it a Component
- Make it a Reusable Part (you are here)
- Does Your Component Really Need to Know That?
- Some Abstractions Aren’t (Just) For Your App
- Reusable and Scaleable Data Management/And, in the end...
- See the app in action
Special thanks to the team at Open Web Components for the great set of tools and recommendations that they’ve been putting together to support the ever-growing community of engineers and companies bringing high-quality web components into the industry. Visit them on GitHub and create an issue, submit a PR, or fork a repo to get in on the action!
Top comments (0)