<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Andrew Beng</title>
    <description>The latest articles on Forem by Andrew Beng (@andrewbeng89).</description>
    <link>https://forem.com/andrewbeng89</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F546269%2Fd62c8248-12c1-4f14-af8f-ad76df136d7e.jpg</url>
      <title>Forem: Andrew Beng</title>
      <link>https://forem.com/andrewbeng89</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/andrewbeng89"/>
    <language>en</language>
    <item>
      <title>Developing and Testing Web Components</title>
      <dc:creator>Andrew Beng</dc:creator>
      <pubDate>Thu, 14 Oct 2021 00:50:27 +0000</pubDate>
      <link>https://forem.com/factorial-io/developing-and-testing-web-components-224a</link>
      <guid>https://forem.com/factorial-io/developing-and-testing-web-components-224a</guid>
      <description>&lt;p&gt;This blog is a follow up from my previous article &lt;a href="https://www.factorial.io/en/blog/custom-elements-vue-reactivity"&gt;"Custom Elements with Vue Reactivity"&lt;/a&gt;. Here I will be sharing my thoughts on the challenges I faced setting up development and unit testing environments, while not forgetting about accessibility concerns for a Web Components project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thinking about Developer Experience
&lt;/h2&gt;

&lt;p&gt;As Vue.js developers, we are spoiled when it comes to &lt;a href="https://developerexperience.io/practices/good-developer-experience"&gt;developer experience&lt;/a&gt; (DX), or “the experience developers have while using or working on your product”. From first-class documentation, to browser extension based or standalone Vue developer tools, to opinionated packages for routing, state management and unit testing, Vue’s ecosystem has always been developer centric, and newcomer friendly. Good DX is therefore a key value software project maintainers should work towards for long-term sustainability of their projects or their developer community.&lt;/p&gt;

&lt;p&gt;When experimenting with Custom Elements in developing &lt;a href="https://github.com/andrewbeng89/vue-uhtml"&gt;vue-uhtml&lt;/a&gt;, the lack of (or at least the lack of documentation of) developer tooling with decent DX became quickly apparent. To date, there is now default or opinionated out-of-the-box solution for web developers to spin up a basic development server to serve vanilla HTML, CSS and JavaScript - the underlying web technologies Custom Elements builds upon. I chose to scope the developer experience considerations for the vue-uhtml project to three areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How might developers use vue-uhtml to develop a UI library&lt;/li&gt;
&lt;li&gt;How might developers unit test components built with vue-uhtml&lt;/li&gt;
&lt;li&gt;How might developers be aware of accessibility issues when developing with vue-uhtml&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A dev environment for Custom Elements projects
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://storybook.js.org/"&gt;Storybook&lt;/a&gt; is a popular and easy-to-use open source tool for building UI components in isolation. Given my previous experience in using Storybook for Vue based projects, this was a natural option for UI development with vue-uhtml. Storybook’s Web Components flavour made this decision an even easier one since this is officially supported and well documented. One possible drawback when using &lt;a href="https://storybook.js.org/docs/web-components/get-started/introduction"&gt;Storybook for Web Components&lt;/a&gt; is the use of the lit-html templating utility to create “stories” for your components. The lit-html project is incidentally the library Evan You chose to implement his own Custom Elements project with. In the case of this project, having to implement components in a slightly different uhtml syntax and “stories” in the lit-html syntax is objectively a negative developer experience, and has to be considered further for a wider vue-uhtml developer community.&lt;/p&gt;

&lt;p&gt;A major hurdle to overcome when developing Custom Elements is an approach for implementing styles and CSS via the encapsulated Shadow DOM, especially when also using CSS pre and post processors. This issue is usually solved during the build process when tools like Webpack or Rollup orchestrate CSS transformations before bundling and injecting processed styles in the right place. Front-end framework CLI tools like vue-cli-service, Vite or create-react-app abstract much of the underlying processing and building for both development and production environments. For example, most Vue developers would not need to be concerned with how a Vue single file component gets compiled by Webpack or Vite and served on a local port when &lt;code&gt;yarn serve&lt;/code&gt; is run. This is great DX, but probably not something that would be easily achievable for vue-uhtml development in the short term.&lt;/p&gt;

&lt;p&gt;Putting the pieces together, these were the steps I took to set up a Storybook based development environment with decent DX to build UI components with vue-uhtml:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configure a bare bones &lt;a href="https://github.com/andrewbeng89/vh-ui-components/blob/main/rollup.config.js"&gt;Rollup project&lt;/a&gt; to process vue-uhtml defined Custom Elements for both development and production&lt;/li&gt;
&lt;li&gt;Configure Rollup to &lt;a href="https://github.com/andrewbeng89/vh-ui-components/blob/main/rollup.config.js#L35"&gt;watch the &lt;code&gt;src&lt;/code&gt; directory&lt;/a&gt; to compile the components to a &lt;code&gt;dev&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;Configure Storybook for Web Components and write &lt;a href="https://github.com/andrewbeng89/vh-ui-components/blob/main/src/components/UiCheckBox.stories.js"&gt;component stories&lt;/a&gt; using the rolled-up output component definitions in the &lt;code&gt;dev&lt;/code&gt; directory (rather than &lt;code&gt;src)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run Rollup and Storybook concurrently via a &lt;a href="https://github.com/andrewbeng89/vh-ui-components/blob/main/package.json#L51"&gt;&lt;code&gt;dev&lt;/code&gt; script&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// UiCheckBox.stories.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lit-html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineUiCheckBox&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../dev/index.esm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;defineUiCheckBox&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Components/UiCheckBox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;ui-check-box&amp;gt;&amp;lt;/ui-check-box&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trial and error in setting up these steps could in the future be the basis for vue-uhtml’s own CLI, or to extend or use Vite for a similar purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit testing Custom Elements
&lt;/h2&gt;

&lt;p&gt;The next consideration I addressed was being able to easily write and run unit tests for vue-uhtml components. Having previously talked about a &lt;a href="https://www.factorial.io/en/blog/unit-testing-vuejs-theory-practice"&gt;unit testing approach for Vue.js components&lt;/a&gt;, I was keen to apply the principle of “writing tests that assert your component’s public interface”. Before I could even think about writing component tests, I had to pick the most appropriate and well supported tooling. Vue’s documentation on testing and own vue-test-utils package makes this choice a foregone conclusion with Jest as a comprehensive test framework, and using vue-test-util’s wrapper based API to mount components in an isolated jsdom environment. While jsdom has provided a &lt;a href="https://github.com/jsdom/jsdom/releases/tag/16.2.0"&gt;Custom Elements implementation since version 16&lt;/a&gt;, other Web Components APIs including Shadow DOM are not supported or reliable enough to be useful.&lt;/p&gt;

&lt;p&gt;Since Custom Elements is a browser based web technology, a common approach to work around jsdom’s limitations is to consider using Puppeteer to run tests on Custom Elements rendered in real browsers. However, in practice this usually isn’t the most practical solution as “boilerplate” code is required to navigate to the components on a served HTML page.&lt;/p&gt;

&lt;p&gt;To improve DX and streamline the unit testing approach for Custom Elements, the folks at Open Web Components have provided an opinionated testing package aptly called &lt;a href="https://open-wc.org/docs/testing/testing-package/"&gt;@open-wc/testing&lt;/a&gt; that “combines and configures testing libraries to minimize the amount of ceremony required when writing tests”. While not having a choice of test runner or assertion library (@open-wc/testing uses Mocha and Chai respectively with Puppeteer) may seem restrictive, the positive trade-off is clear documentation and concise examples to help get up and running writing component tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential gotcha: &lt;code&gt;shadowRoot.mode&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The encapsulation of Custom Element features is aided by the ability to set a component’s &lt;code&gt;shadowRoot&lt;/code&gt; mode to &lt;code&gt;”closed”&lt;/code&gt;, preventing the shadow root's internal features being accessible from JavaScript. This is a feature that is set to &lt;a href="https://github.com/andrewbeng89/vue-uhtml/blob/main/src/main.js#L27"&gt;&lt;code&gt;“closed”&lt;/code&gt; by default&lt;/a&gt; when building components with vue-uhtml. This has potential “gotcha” implication in preventing test scripts from asserting the components’ internal features. To prevent falling into this trap, components based on Custom Element should easily allow developers to be &lt;a href="https://github.com/andrewbeng89/vh-ui-components/blob/main/src/components/UiCheckBox.js#L63"&gt;defined with an &lt;code&gt;”open”&lt;/code&gt; shadow root mode&lt;/a&gt; when used in tests.&lt;/p&gt;

&lt;p&gt;The example below outlines tests for a custom checkbox component which:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Asserts that the initial &lt;code&gt;checked&lt;/code&gt; value is &lt;code&gt;false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Asserts that the &lt;code&gt;checked&lt;/code&gt; value is &lt;code&gt;true&lt;/code&gt; if its attribute is passed&lt;/li&gt;
&lt;li&gt;Asserts that the &lt;code&gt;checked&lt;/code&gt; value is &lt;code&gt;true&lt;/code&gt; after the input is clicked
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;elementUpdated&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@open-wc/testing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineUiCheckBox&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../dist/index.esm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;defineUiCheckBox&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;isTest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UiCheckBox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;has a default checked value which is falsy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;` &amp;lt;ui-check-box&amp;gt;&amp;lt;/ui-check-box&amp;gt; `&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;has a checked of true when the 'checked' attribute is passed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;` &amp;lt;ui-check-box checked&amp;gt;&amp;lt;/ui-check-box&amp;gt; `&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;has checked value after click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;` &amp;lt;ui-check-box&amp;gt;Checkbox&amp;lt;/ui-check-box&amp;gt; `&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;elementUpdated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Developing with &lt;code&gt;a11y&lt;/code&gt; in mind
&lt;/h2&gt;

&lt;p&gt;Web accessibility (&lt;code&gt;a11y&lt;/code&gt;) has historically been an area overlooked by developers and designers alike, often seen as more of an art than precise science. While there is no single tool or methodology that solves all &lt;code&gt;a11y&lt;/code&gt; concerns for web development, significant progress in tooling has made it possible to integrate &lt;a href="https://www.w3.org/WAI/standards-guidelines/wcag/"&gt;Web Content Accessibility Guidelines&lt;/a&gt; (WCAGs) into development workflows. Although the use of such developer tools does not solve the actual task of authoring accessible websites and apps, they do help developers become more aware of the &lt;code&gt;a11y&lt;/code&gt; topic during development rather than after. One such tool at the forefront of this drive to assist developers in developing with &lt;code&gt;a11y&lt;/code&gt; is axe, which provides an open-source accessibility rule set for automated accessibility validation. The axe rule set can in turn be used in &lt;code&gt;a11y&lt;/code&gt; validation plugins in other developer tools. I was able to easily integrate an axe based &lt;a href="https://open-wc.org/docs/testing/chai-a11y-axe/"&gt;&lt;code&gt;a11y&lt;/code&gt; plugin for Chai with @open-wc/testing&lt;/a&gt; into my vue-uhtml components project.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.npmjs.com/package/chai-a11y-axe"&gt;axe plugin for Chai&lt;/a&gt; allows developers to automatically run &lt;code&gt;a11y&lt;/code&gt; validation as part of their TDD or BDD workflow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Take-aways
&lt;/h2&gt;

&lt;p&gt;Thinking about developer experience in the context of developing a Custom Elements based project has been a lot like thinking about user experience when developing front-end websites and applications. Instead of a visual user interface, a tool/library/framework’s API is the end user’s (in this case developer’s) medium for achieving their tasks. This small exercise in DX has made me appreciate the thoughtful contributions open source maintainers make in keeping their tools and documentation easy to use for the wider developer community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.factorial.io/en/blog/custom-elements-vue-reactivity"&gt;Custom Elements with Vue Reactivity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.factorial.io/en/blog/unit-testing-vuejs-theory-practice"&gt;Unit Testing in Vue.js: From Theory into Practice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/andrewbeng89/vh-ui-components"&gt;Demo project repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vue</category>
      <category>webdev</category>
      <category>testing</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Custom Elements with Vue Reactivity</title>
      <dc:creator>Andrew Beng</dc:creator>
      <pubDate>Thu, 08 Jul 2021 08:22:31 +0000</pubDate>
      <link>https://forem.com/factorial-io/custom-elements-with-vue-reactivity-25o1</link>
      <guid>https://forem.com/factorial-io/custom-elements-with-vue-reactivity-25o1</guid>
      <description>&lt;p&gt;The 13th Hamburg Vue.js Meetup was held last week, this time as an online live-stream due to the ongoing COVID-19 restrictions. I was pleased to represent Factorial to share a talk on some insights on a small experiment in building Custom Elements with Vue 3.x’s standalone Reactivity module. Having previously worked with Vue’s own &lt;a href="https://cli.vuejs.org/guide/build-targets.html#web-component"&gt;Custom Elements build option&lt;/a&gt;, I was keen to re-explore this topic with standalone Reactivity, also spurred on by Evan You’s &lt;a href="https://github.com/yyx990803/vue-lit#vuelit-"&gt;~70 lines-of-code experiment&lt;/a&gt;. My own question was, “could it really be that simple?”&lt;/p&gt;

&lt;h2&gt;
  
  
  Vue 3.x Reactivity
&lt;/h2&gt;

&lt;p&gt;Vue’s Reactive utility (previously known as Vue.observable) has been heavily overhauled since the release of Vue 3 late in 2020. Its dependency to ES6 Proxy makes observing state changes a breeze for developers, but also means that Vue 3 drops support for Internet Explorer 11.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Elements
&lt;/h2&gt;

&lt;p&gt;Custom Elements is a foundational Web Components which allows developers to create and extend HTML tags. The main goal of the Custom Elements API is in creating reusable components (an objective shared with front-end libraries and frameworks like Vue, React, or Angular), using web standards: HTML, CSS and JavaScript. In using web standards, the biggest advantage of using Custom Elements is their easy interoperability in other framework specific projects, e.g. sharing the same Custom Elements across Vue or React projects. &lt;/p&gt;

&lt;p&gt;In practice, creating vanilla Custom Elements often involves writing lots of boilerplate code, especially when setting up reactive properties and observed attributes. This is something which is solved in some of the &lt;a href="http://webcomponents.dev/new/"&gt;wide array of Custom Elements libraries and frameworks&lt;/a&gt; available. Addressing the issue of verbose boilerplate code is also an area where standalone Reactivity shines.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “vue-micro” Experiment
&lt;/h2&gt;

&lt;p&gt;My experiment in creating a framework to build Custom Elements borrows from Vue creator Evan You’s own proof of concept called &lt;a href="https://github.com/yyx990803/vue-lit"&gt;vue-lit&lt;/a&gt;. The goals of my vue-uhtml (“vue-micro”) experiment were to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add props validation&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; interface&lt;/li&gt;
&lt;li&gt;Implement some form of test coverage&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The pseudo code below provides an overview of how the Custom Elements API is used to emulate the rendering and reactive features seen in Vue components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;observedAttributes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Return a list of observed attribute names&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Scaffold reactive props&lt;/span&gt;
        &lt;span class="c1"&gt;// 2. Scaffold slots as reactive object&lt;/span&gt;
        &lt;span class="c1"&gt;// 3. Apply effect to render the template + run hooks&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Run beforeMount hook&lt;/span&gt;
        &lt;span class="c1"&gt;// 2. Render template + invoke setup()&lt;/span&gt;
        &lt;span class="c1"&gt;// 3. Run mounted hook&lt;/span&gt;
        &lt;span class="c1"&gt;// 4. Bind template slots to reactive object&lt;/span&gt;
        &lt;span class="c1"&gt;// 5. Validate props&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;disconnectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Run unmounted hook&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;attributeChangedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Parse, validate and update reactive props&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[Pseudo code structure of vue-uhml - JavaScript]&lt;br&gt;
View the actual code &lt;a href="https://github.com/andrewbeng89/vue-uhtml/blob/main/src/main.js"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s an example of vue-uhtml in action combining reactive re-rendering on user input, props validation, and using a named &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/andrewbeng89/embed/RwVwMXJ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I spent some time researching how Custom Elements could be test-automated. The community driven Open Web Components initiative provides a set of defaults, recommendations and tools to help facilitate web components projects. The @open-wc/testing package combines and configures testing libraries to quickly get up to speed writing tests for Custom Elements. The vue-uhtml repository includes &lt;a href="https://github.com/andrewbeng89/vue-uhtml/tree/main/test"&gt;tests&lt;/a&gt; for a Custom Element built with vue-uhtml covering lifecycle hooks, user input and props interfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take-aways and possible future
&lt;/h2&gt;

&lt;p&gt;To conclude the talk, I shared my top three take-aways from this experiment with the Vue.js Hamburg:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Standalone Vue Reactivity is pretty awesome&lt;/li&gt;
&lt;li&gt;Custom Elements are not scary&lt;/li&gt;
&lt;li&gt;More developers should also get out there and experiment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My learning experience through this process of experimenting with community driven open source software far outweighed the extent of checking off the original goals I had set out. I was encouraged on this point that the second talk of the evening by Thomas Jacob from sum.cumo (“VueGround: Ein Design-Tool und Playground für Vuetify, in Vuetify”) was also in the spirit of experimentation.&lt;/p&gt;

&lt;p&gt;Writing user centric documentation and more comprehensive test coverage for vue-uhtml are two areas to focus on before vue-uhtml to be “production ready”. Whether vue-uhtml will be added to the wide selection of Custom Elements frameworks already available remains a question for the wider developer community to engage with.&lt;/p&gt;

&lt;p&gt;Many thanks to Vue.js Hamburg and Joe Ray Gregory for organising this online Meetup, and to sum.cumo for the smooth hosting of the live-stream on YouTube. We are indeed looking forward to the day when in-person Vue.js Hamburg meetups will be possible again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://slides.com/andrewbeng89/vue-reactivity-custom-elements"&gt;Talk slide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/andrewbeng89/vue-uhtml"&gt;vue-uhtml repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vue</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
