custom-elements-everywhere scores frameworks on how they treat Custom Elements
Custom Element + Framework Interoperability Tests.
At a glance
- What is it?
- This project is a Karma test suite that runs the same custom element tests against more than twenty UI libraries and frameworks, then publishes the results as a comparison site. It is aimed at engineers deciding whether a framework can consume web components, and at framework maintainers who want to see where their implementation falls short.
- Who is it for?
- custom-elements-everywhere is the project to consult before committing a framework to a web components strategy, because it tests the same behaviours against every listed library instead of taking marketing claims at face value.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One shared test suite, run once per framework, published as a scoreboard
The project answers a narrow question that framework documentation rarely answers directly: when a framework renders or consumes a custom element, does it actually respect the custom element contract? The answer is produced by running Karma tests, so the comparison is behavioural rather than a matter of opinion. Every framework in the list is given the same set of custom elements from a shared directory and the same assertions, and the outcome is a summary score that ends up on the site. The shared custom elements live in the libraries/__shared__/webcomponents directory, and every framework uses them for its tests, which is what makes the numbers comparable at all. The result is a public comparison site rather than a library you install, and the repository description in the root package.json puts it plainly: Compare how different frameworks handle Web Components. It is a test harness with a website attached, not a polyfill or a shim.
Twenty-two frameworks, from React and Angular to Skate and Dio
The current list of libraries and frameworks covers a wide spread of styles and ages. Angular and AngularJs are both present, and so are React, Preact, Vue, Svelte, Solid, Lit, Polymer, Stencil, LWC and Mithril. Less common options are listed too, including Dio, Dojo, Hybrids, Hyperapp, HyperHTML, Omi, Riot.js, Skate and Surplus. The presence of both Angular and AngularJs, and of both Preact and Skate, matters when you read the results, because the frameworks have different architectures and different native support for custom elements. Each entry has its own directory under libraries, which is where its tests, its package manifest and its metadata live.
The assumed behaviours are about shadow DOM, primitive and rich data, and DOM events
The suite assumes a specific set of capabilities, and knowing them tells you what a score actually means. A framework should be able to display elements that use shadow DOM, insert children into them, and handle hiding and showing them. It should be able to pass primitive data, meaning strings, numbers and booleans, to a custom element as either attributes or properties. It should be able to pass rich data, meaning objects and arrays, using properties. And it should be able to listen to DOM events from a custom element, where the events could use any casing style. That last point is a common source of real bugs, since a framework that normalises event names differently from the custom element will deliver a listener that never fires. The list is short and specific, which is a strength: the score reflects a handful of concrete obligations rather than a vague measure of compatibility.
Adding a framework means copying a directory and wiring a build script
The contribution guide is written as a numbered procedure, and the first step is copy an existing example. Tests for each library live in the libraries directory, and the guidance is to start from whichever project is closest to yours, for example copying and renaming the libraries/preact directory if your library is similar to React or Preact. The expected structure is fixed.
βββ .babelrc
βββ karma.conf.js
βββ meta
β βββ issues.json
β βββ summary.md
βββ package-lock.json
βββ package.json
βββ src
β βββ advanced-tests.js
| βββ basic-tests.js
β βββ components.js
βββ tests.webpack.jsThe package.json for the new library must contain build and test npm scripts, and the test script is the one that actually runs Karma. It also has to set a variable, LIBRARY_NAME, matching the npm package name of the library, because the build process uses it to grab the library's semver and publish it on the site.
"scripts": {
"test": "cross-env LIBRARY_NAME=@angular/core karma start",
"build": "npm run test"
}The meta directory holds issues.json, where you list open GitHub issues about custom element support in that library, and summary.md, a short description of how the library interacts with custom elements plus known quirks and gotchas. The src directory holds components.js, where you write framework components that try to communicate with the custom elements, and you then test them in basic-tests.js and advanced-tests.js, using all the assertions in the test files while updating the actual implementations to use your own components.
update-goldens turns a score change into a reviewable diff
The third step of the contribution guide is the one that makes the whole comparison trustworthy. In the root of the project you run npm run update-goldens, which generates an expectedResults.json file for your library's tests. The stated purpose is that any change producing a different summary score for any library shows up in code review, and any change that would accidentally alter a summary score makes the tests fail. That is a golden file approach, and it is the reason a silent behaviour change in a dependency cannot quietly rewrite the leaderboard. Step two of the guide covers the wiring that makes this work: you add an install- script to the root package.json and run it during the install script, you update the build script in the libraries directory package.json to include your library's name, and a test runner called index.js in the project root detects a new folder under libraries and attempts to run that folder's build command. In other words, the site is a build product, regenerated from a list of directories.
The root build is a wireit graph, not a hand written script list
The current root package.json delegates nearly every script to wireit rather than running commands directly, and the dependency list is the interesting part. build, copy-and-verify-results, update-goldens, test, start and karma-plugins are all defined as wireit entries. The copy-and-verify-results entry lists an explicit dependency on each library's build, one line per framework, from ./libraries/angular:build through ./libraries/vue:build, and it declares its output as docs/libraries, with the command node scripts/copy-and-verify-results.mjs. The test entry depends on build, and the build entry depends on ./docs:build, so the site is compiled from the docs workspace. The workspaces array covers libraries/*, libraries/__shared__/*, libraries/__shared__/karma-plugins/* and docs, and the devDependencies include chai for assertions, fs-extra, http-server for previewing, node-fetch and minimist, along with babel core and wireit itself. The script name is the interesting part: it both builds and verifies, which is why a drifted golden file is a build failure rather than a separate check you might forget to run.
Getting the site running locally is three npm commands
The installation section is deliberately terse, and it is worth reproducing because it is the only thing a visitor needs to run the whole comparison locally. The site is a set of static files with a build step behind it, and the preview is served locally.
# Install all the things!
npm ci
# Test all the things!
npm run build
# Preview the site.
npm startnpm ci installs all dependencies from the lockfile, npm run build runs the wireit build, which as shown above fans out to every library's build and then to the docs workspace, and npm start previews the site. The repository root holds a package-lock.json, a renovate.json, a scripts directory and a docs directory alongside libraries, and the presence of renovate.json is worth a note, since dependency bumps across twenty-one framework test suites are exactly the kind of maintenance that decays without automation. A separate question is how the site itself is deployed.
The score tells you where a framework falls short, not how to fix it
The limitation that matters most is scope. This project measures, it does not repair. If a framework fails an assertion about setting a property on a custom element, the correct entry is an open GitHub issue in that framework's tracker, and the meta directory of each library is where those references are recorded, alongside the quirks and gotchas described in summary.md. A separate limitation is the one you hit when your framework is not on the list. Adding it means copying a directory, rewriting components.js for your own component model, writing a summary, and wiring the root scripts, which is a real contribution rather than a configuration flag. The list also freezes at the versions each entry was recorded against, and there is no GitHub releases history for the repository, so there is no tagged version to pin to, which is a genuine problem for anyone who wants to reproduce a specific score table.
Editorial conclusion
custom-elements-everywhere is the project to consult before committing a framework to a web components strategy, because it tests the same behaviours against every listed library instead of taking marketing claims at face value. It is the wrong tool if you need a fix for a failing framework, since nothing here patches the libraries it measures, and it is a poor fit for a framework that is not in the list, because adding one is a multi step contribution rather than a configuration change. Before trusting a score, read the summary and quirks recorded for that library, and check the framework version the entry was recorded against. The root package.json declares an Apache 2.0 licence while the repository licence is one GitHub cannot classify, so check the LICENSE file before redistribution. The last push was on 2026-10-13 and the repository has no GitHub releases.
Frequently asked questions
What does custom-elements-everywhere test?
It runs Karma tests for each major framework to see how they handle working with Custom Elements. The assumed behaviours are displaying elements that use shadow DOM, inserting children in them, passing primitive data as attributes or properties, passing rich data through properties, and listening to DOM events from a custom element.
How do I run the custom-elements-everywhere site locally?
Run npm ci to install dependencies, npm run build to run the tests and build the site, and npm start to preview it. The root scripts are wired through wireit, so the build fans out to each library's own build before the docs are compiled.
How do I add a new framework to custom-elements-everywhere?
Copy the closest existing library directory under libraries, for example libraries/preact, and rename it. Your package.json needs build and test scripts, and the test script must set LIBRARY_NAME to your npm package name so the build can pick up the semver.
What is the purpose of npm run update-goldens?
It generates an expectedResults.json file for your library's tests. Any change that results in a different summary score shows up in code review, and any change that would accidentally change the summary score makes the tests fail.
Which frameworks are covered by custom-elements-everywhere?
The listed libraries include Angular, AngularJs, Dio, Dojo, Hybrids, Hyperapp, HyperHTML, Lit, LWC, Mithril, Omi, Polymer, Preact, React, Riot.js, Skate, Solid, Stencil, Surplus, Svelte and Vue. Each one has its own directory under libraries with its own tests and metadata.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/webcomponents-custom-elements-everywhere)Was this useful?