Learning web components and PatternFly Elements

Today at Red Hat is day of learning again! I used the occasion to brush up my knowledge about web components and taking a look at PatternFly Elements. I’ve leered at that for a long time already – using “regular” PatternFly requires React, and thus all the npm, bundler, build system etc. baggage around it.

In Cockpit we support writing your own plugins with a simple static .html and .js file, and how cool would it be to let them have the usual PatternFly look to blend in with all the other pages? Also, these days the web platform really supports all the concepts that React introduces, which means there’s a lot less code to load into the browser if you just use plain web components.

They may not be very visible and some may even declare them “dead”, but they very much aren’t. 😀

Static webpage with PatternFly Elements

I started with updating my old PatternFly CDN demo (source) to the current version 4. That now requires using an import map, which were entirely new to me. With them you can use the usual import "@namespace/module" on your page without using a bundler – how amazing! This CDN model is completely fine for a quick-and-dirty webpage with minimal effort.

A self-contained version of that uses local npm modules. I made a demo for that as well – you need to check it out, run npm install, then start a web server on it (npm run-script run will use Python’s http.server), and look at it on http://localhost:8080 (file:// does not work in that situation).

Cockpit starter-kit

starter-kit is a demo extension for Cockpit that gives you a ready-to-run project with all the bells and whistles: npm modules, build system, translations, linting, and browser integration tests on a dozen OSes and multiple browsers. Like every other official Cockpit page this also uses PatternFly 5 and React.

I created a starter-kit branch/PR that uses PatternFly Elements and Lit instead, which was pleasantly straightforward. The size reduction is quite impressive:

  • index.js.gz shrinks from 80 kB to 29 kB. This includes the PatternFly CSS!
  • index.css.gz, which was previously 23 kBytes, disappears entirely.
  • node_modules shrinks from 381 MB to 202 MB.

My main trouble was with the tests: they were broken because the standard document.querySelectorAll() cannot pierce through shadow DOMs (and is not supposed to). The top-level DOM is now just a single <ct-application /> tag, which of course contains a lot more shadow DOMs for each PF element.

After some research I picked the query-selector-shadow-dom NPM module which provides a convenient querySelectorAllDeep() API that makes shadow DOM pretty much transparent. I.e. tests don’t have to know/specify at which point the shadow DOM boundaries are in a selector. I sent PR#21233 to teach our testlib about it.

With that, my starter-kit PFE branch works end-to-end, including running the tests locally and in our CI. They still fail on the Testing Farm for some subtle reason, I’ll investigate that next week.

PatternFly Elements development

After that I turned my attention to the patternfly-elements project itself. I worked through the development setup, played around with the dev server, tests, demos, and adding a new example component. During that I noticed that npm new generates a broken template with two TypeScript errors. I reported a bug about that and sent PR#2873 to fix it.

The main thing that holds us back is that there are still a lot of components missing compared to PatternFly React, such as Alert, Checkbox, or TimePicker.

For the missing Alert there is already an upstream issue and an old PR. I dusted this off, cleaned it up, and worked on that for about two hours until everything built and the demos worked. However, there’s still a lot more to be done before it’s ready for a PR. For the time being I pushed it to my fork.