<?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>DEV Community: Ivan</title>
    <description>The latest articles on DEV Community by Ivan (@pinguxx).</description>
    <link>https://dev.to/pinguxx</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%2F60874%2F62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg</url>
      <title>DEV Community: Ivan</title>
      <link>https://dev.to/pinguxx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pinguxx"/>
    <language>en</language>
    <item>
      <title>Easy apps with hyperHTML — 10, 3rd party libraries</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Fri, 07 Jun 2019 14:57:43 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b</guid>
      <description>&lt;p&gt;Part 10 written by &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F60874%2F62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171460%2F77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;Introduction, wire/bind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;Events and components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;Moar about components and simple state management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;Wire types and custom definitions (intents)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-5hdl-temp-slug-7285698"&gt;Custom elements with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-h5b-temp-slug-4579110"&gt;Customizing my custom elements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-12g4-temp-slug-5472234"&gt;Testing!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96"&gt;Async loading, placeholder and a Typeahead with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0"&gt;Handling routes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3rd party libraries&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq1bejwaip8ahozvruzh6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq1bejwaip8ahozvruzh6.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;
Photo by &lt;a href="https://unsplash.com/photos/C0koz3G1I4I?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Markus Spiske&lt;/a&gt; on &lt;a href="https://unsplash.com/search/photos/block?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;



&lt;p&gt;Combining third-party libraries with your framework can often be challenging. Because hyperHTML is built on JavaScript standards, using it with other libraries is generally pain-free and easy. This is one of the chief beauties of hyper: it plays well with others.&lt;/p&gt;

&lt;p&gt;In part 4 we saw how to define and use intents. In part 2, we worked with components, and in part 5 we looked at custom elements.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you missed any of those parts, head back now and review them. We’ll build on what we learned there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Today, we are going to use 3rd party libraries to spice up all three of these. Just load ‘n use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time 📅 and intents 😉
&lt;/h3&gt;

&lt;p&gt;To start, we are going to use &lt;a href="https://github.com/iamkun/dayjs" rel="noopener noreferrer"&gt;dayjs&lt;/a&gt;. Dayjs is a simpler and smaller alternative to &lt;a href="https://momentjs.com/" rel="noopener noreferrer"&gt;moment.js&lt;/a&gt;. If you’re looking for a datetime library with a smaller footprint, a familiar and logical API, dayjs is a great choice. Back in part 4 we had a date format intent that was printing a date in a specific format. It looked like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now lets update it to use dayjs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import dayjs from 'dayjs';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here’s our first attempt to use the intent:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-3rd-01?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;But we now have the full power of dayjs, so why stop here? We can add formatting options to our intent. Check this out:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-3rd-02?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you were expecting another step or two, prepare to be disappointed! That’s all there is to using dayjs inside your intents.&lt;/p&gt;
&lt;h3&gt;
  
  
  Emojis 😊 and Components ✔️
&lt;/h3&gt;

&lt;p&gt;We’ve already covered the basics of including 3rd party libraries. To add some fun to our components, we are going to convert some text strings to emojis using the &lt;a href="https://github.com/joypixels/emojify.js" rel="noopener noreferrer"&gt;emojify&lt;/a&gt; library. If you’re following along at home, go ahead and import the library into a new file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Emojify will detect things like :) and 😄 and convert it to an emoji image. See this &lt;a href="https://www.webfx.com/tools/emoji-cheat-sheet/" rel="noopener noreferrer"&gt;cheat sheet&lt;/a&gt; for more information on what it can do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s start with a simple component using &lt;code&gt;hyper.Component&lt;/code&gt;. This component is going to receive some text, and then &lt;code&gt;onclick&lt;/code&gt; we are going to use emojify to parse and show emojis. The magic happens in this line&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;emojify.replace(this.text);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This component is very simple. We pass in text when we construct the component, and save in two places: &lt;code&gt;this.text&lt;/code&gt; is what we will transform, and we’ll keep it around in &lt;code&gt;this._original&lt;/code&gt; so we can revert if we need to.&lt;/p&gt;

&lt;p&gt;That too, was easy! Nothing else to do. The full source code:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-3rd-03?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
&lt;h3&gt;
  
  
  Charts 📊 and Custom Elements 🎉
&lt;/h3&gt;

&lt;p&gt;Lastly, we are going to create charts with the amazing library &lt;a href="https://gionkunz.github.io/chartist-js/index.html" rel="noopener noreferrer"&gt;chartist&lt;/a&gt;. Chartist allows us to easily create simple or advanced charts. Just give it data and options, start a new chart of the type you want, and voila! This chart element is not complicated, but it is more involved than the intent and component we made earlier. We’ll just hit the highlights of it here.&lt;/p&gt;

&lt;p&gt;As always, first load the package. For chartist to work, we also need to load some CSS.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "chartist/dist/chartist.css";
import Chartist from "chartist";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The only attribute we are going to observe is the type; everything else will be plain getters and setters. We’ll need a get/set for data and for options. We’ll also include a get/set for both called details to make it easy to update everything in one call.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;As you can see, we are calling update on every attribute change. This update function is going to either create a chart, or if we already have one, update it. Variables are created in the created() function and updated in render() .&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;All we’re doing here is creating and storing a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; in &lt;code&gt;this._el&lt;/code&gt;, and starting a chart instance.&lt;/p&gt;

&lt;p&gt;To use this element, we will have a custom-chart element in the page with the type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;custom-chart type="Line"&amp;gt;&amp;lt;/custom-chart&amp;gt;
&amp;lt;custom-chart type="Bar"&amp;gt;&amp;lt;/custom-chart&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then we can pass data and options to make it render the actual chart&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Full code for the element and example of usage&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-3rd-04?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;What? We’re already done with this part? There’s no crazy hoops to jump through to add 3rd-party libraries to hyperHTML? There’s no magic code dance we have to do? No library-author to ping for an update/change/bugfix? Nope. HyperHTML does a fantastic job of incorporating other libraries. And why would we expect anything different — hyper is standards-based vanilla JavaScript.&lt;/p&gt;

&lt;p&gt;Hopefully we’ve done a good job helping you see the power of combining hyperHTML with some of your favorite libraries. Let us know in the comments what amazing applications you create using hyperHTML.&lt;/p&gt;

&lt;p&gt;This is the last part of our series on hyperHTML. We will keep writing about hyperHTML in other posts, so let us know if there are topics you want to see covered. We hope you enjoyed this journey as much as we enjoyed writing it. Thanks for reading.&lt;/p&gt;




</description>
      <category>hyperhtml</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Easy apps with hyperHTML — 9, routing</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Thu, 06 Jun 2019 15:17:09 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0</guid>
      <description>&lt;p&gt;Part 9 written by &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F60874%2F62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171460%2F77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;Introduction, wire/bind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;Events and components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;Moar about components and simple state management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;Wire types and custom definitions (intents)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-5hdl-temp-slug-7285698"&gt;Custom elements with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-h5b-temp-slug-4579110"&gt;Customizing my custom elements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-12g4-temp-slug-5472234"&gt;Testing!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96"&gt;Async loading, placeholder and a Typeahead with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handling routes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b"&gt;3rd party libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AadsYsCwwYGzqLIhnP5AD6Q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AadsYsCwwYGzqLIhnP5AD6Q.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you missed any of the previous parts, now’s a good time to catch up on the ones you missed. Specifically, part 9 builds upon part 8. Recall that we built a table in part 8 and populated it with real data from the cryptocompare api. Now that we are retrieving real data, we can enhance our application even more. This application is a good candidate for routes. By using routes, we can turn it into a single page application or SPA. SPAs don’t need to reload the whole page every time we want to display different parts of the application.&lt;/p&gt;

&lt;p&gt;This is our application so far:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-app-03?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We are going to add a new tab to display the historical data for the selected coin in the dropdown. To do this, we are going to use state management, our elements, and route management.&lt;/p&gt;




&lt;h3&gt;
  
  
  Reorganization
&lt;/h3&gt;

&lt;p&gt;So far we have only used a few elements on the same page. While this is easy to manage, we now need better organization to handle routes and different elements working together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F205%2F1%2AS1ik3vMIJxSjvLrqrKBfjw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F205%2F1%2AS1ik3vMIJxSjvLrqrKBfjw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are going to create a folder called elements and move the ones we’ve already created into it. Same with intents. Don’t forget: since we changed the paths we need to update our import statements for all of them.&lt;/p&gt;

&lt;p&gt;Also, let’s create a components folder. We’ll use it soon.&lt;/p&gt;

&lt;p&gt;This is our code now&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-app-04?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h3&gt;
  
  
  Routing
&lt;/h3&gt;

&lt;p&gt;There are a ton of different options for routing and most likely your favorite framework has one… and hyper does as well. And yes it’s YAAT — Yet Another Andrea Tool. &lt;a href="https://github.com/WebReflection/hyperhtml-app" rel="noopener noreferrer"&gt;https://github.com/WebReflection/hyperhtml-app&lt;/a&gt;. You don’t need to use hyper to use this library, and it is similar to the Express framework in how you define the routes.&lt;/p&gt;




&lt;h4&gt;
  
  
  Route types
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;get(“/path/:param”, cb)&lt;/strong&gt;: GET requests to the specified path will be caught. Inside the callback cb, the param will be available as a property on the first argument. e.g: ctx.param&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;use(paths, cb)&lt;/strong&gt;: Adds middleware to the specified paths. This is similar to get, but it accepts an array of paths&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;delete(path, cb)&lt;/strong&gt;: Removes a callback from a path&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;param(name, cb)&lt;/strong&gt;: Allows you to specify a function to use once when a parameter name is passed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;navigate(path)&lt;/strong&gt;: Navigate to the path programatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For our current project, we are will mostly use get, but as you can see, hyperhtml-app has many options for you to use.&lt;/p&gt;

&lt;p&gt;To get started, let’s import the library and create a couple of routes. Because we’ll be adding an index route, we can get rid of the code inside our index.html and index.js files. We’ll replace it with this:&lt;/p&gt;

&lt;p&gt;New index.html&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;New index.js&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;When we spin up the server, clicking on the links shows our messages in the console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Age9mJJEPMI7N6AJI1Qp00w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2Age9mJJEPMI7N6AJI1Qp00w.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s do a quick recap. First, we created an application then we used get (or post or others) to define our paths and a callback. In a real app, the callback will return the view for that path, but for this simple demo, we used it to console.log some text.&lt;/p&gt;




&lt;h4&gt;
  
  
  Components
&lt;/h4&gt;

&lt;p&gt;That was pretty easy! But how about we use some components?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By the way, if you need help with components check out &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;part 2&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are going to create a coins.js file that loads a couple of components.&lt;/p&gt;

&lt;p&gt;Let’s start by making two similar components, compare and info. The only difference between them will be that they display something different. Each of these component will be in their own file, Compare.js and Info.js. Take a look at the Compare component:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Our Info component will be the same, but inside the render() function it will show “Information” and a link to “/”.&lt;/p&gt;

&lt;p&gt;Now coins.js is going to get a bit more complex. First we are going to load both Compare and Info components&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Compare from "./compare";
import Info from "./info";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then in the constructor for the app we are going to create references to our components.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor(app) {
 super();
 this.app = app;
 this.compare = new Compare();
 this.info = new Info();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We also going to create a wire to render them.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.tabc = hyper.wire(this, ":tabcontent")`&amp;lt;div&amp;gt;`;
 this.tabb = hyper.bind(this.tabc);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After adding the default state with coin and path as properties, add an update function that only updates the path for the state. After this we are going to add a &lt;code&gt;renderComponent&lt;/code&gt; function that will render the component based on the route&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;renderComponent() {
 this.tabb`&amp;lt;div&amp;gt;`; //needed for later
 if (this.state.path === "/") {
 this.tabb`${this.compare.update(this.state)}`;
 } else {
 this.tabb`${this.info.update(this.state)}`;
 }
 return this.tabc;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And render&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;render() {
 return this.html`
 &amp;lt;div id="app" class="container-fluid"&amp;gt;
 ${this.renderComponent()}
 &amp;lt;/div&amp;gt;
 `;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We also need to update index.js to render coins.js, and index.html to just have the body element. Take a look at the current state of the code:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-app-05?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;


&lt;h3&gt;
  
  
  Layout
&lt;/h3&gt;

&lt;p&gt;Now that we have our routes, we need to add the rest of the elements to our page. We’ll make a Search component that holds an input for selecting the coin, and some tabs to change between the views of the table and the coin information.&lt;/p&gt;


&lt;h4&gt;
  
  
  Search
&lt;/h4&gt;

&lt;p&gt;For the search we are going to show a “select coin” label along with the input. We won’t start with a coin selected, so at load this is the only thing we are going to show. Let’s take a look at the Search component:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;We have to load this new component in coins.js, and bring back our polyfill and elements to index.js&lt;/p&gt;

&lt;p&gt;index.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "document-register-element";
import './intents/intents.js';
import "./elements/Table.js";
import "./elements/Typeahead.js";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;coins.js:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Search from "./search";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then update coins to render search component&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;${Search.for(this, ":search").update(this.state)}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;… and that uncovered a bug. Having an empty filter its creating an error in typeahead. Do you think you can find and fix this bug? Take a shot at it, but if you get stuck, see the latest code below&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-app-06?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;


&lt;h4&gt;
  
  
  Tabs
&lt;/h4&gt;

&lt;p&gt;For the Tabs component, we will show a couple of tabs that will serve as our app navigation:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;And in the same way as before, import it and render it in coins.js. Now we can see the two views when clicking on the tabs. Check out the code so far:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-app-07?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h3&gt;
  
  
  Complete application
&lt;/h3&gt;

&lt;p&gt;We are almost there! We need to bring our previous elements back to make them work all together.&lt;/p&gt;




&lt;h4&gt;
  
  
  Compare
&lt;/h4&gt;

&lt;p&gt;We have to load the data whenever the user selects a coin from our input. We’ll use the fetch api just like before. We also added a check before render so that we only render the compare table if we have an icon selected.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Back in coins.js, we now have to listen for the user selecting a coin from the input. Let’s add an &lt;code&gt;onchange&lt;/code&gt; to the base div&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div id="app" onchange="${this}" class="container-fluid"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Don’t forget about the event handler itself:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onchange(ev) {
 this.setState({coin: ev.target.value});
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This also uncovers a different bug in the table — columns are not defined when it tries to render. This is a more complex bug, so feel free to check the finished code for the fix.&lt;/p&gt;


&lt;h4&gt;
  
  
  Info
&lt;/h4&gt;

&lt;p&gt;The info tab will also fetch the details for the selected coin from cryptocompare, and then show the icon and the name/fullname with a link.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Since we are not showing the tab view until we select something, let’s also hide the tabs themselves by adding the following conditional in render:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (!this.state.coin) {
 return;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And done! For an exercise, try to follow how we are passing the properties down to each component with the update() function. To pass data back up, we are listening for the events on the top components :D&lt;/p&gt;

&lt;p&gt;See the complete code and application working:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-app-08?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This post took a while to create, but you know life happens. Hopefully you are still reading and as always, clap away and leave your comments and requests below. We are almost done with the series. We hope you like it so far!&lt;/p&gt;




</description>
      <category>javascript</category>
      <category>hyperhtml</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Easy apps with hyperHTML — 8, Async loading</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Wed, 05 Jun 2019 14:04:27 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96</guid>
      <description>&lt;p&gt;Part 8 written by &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
  
    .ltag__user__id__60874 .follow-action-button {
      background-color: #353638 !important;
      color: #FFFFFF !important;
      border-color: #353638 !important;
    }
  
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MvWCfXka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--yF4B1j7T--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/60874/62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://twitter.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="twitter logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--oEHrSmvE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-logo.svg"&gt;pinguxx
        &lt;/a&gt;
        &lt;a href="https://github.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;pinguxx
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
  
    .ltag__user__id__171460 .follow-action-button {
      background-color: #093656 !important;
      color: #FFFFFF !important;
      border-color: #093656 !important;
    }
  
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r4dfAuX5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--NSzkAUjv--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/171460/77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://github.com/paritho" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;paritho
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;Introduction, wire/bind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;Events and components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;Moar about components and simple state management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;Wire types and custom definitions (intents)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-5hdl-temp-slug-7285698"&gt;Custom elements with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-h5b-temp-slug-4579110"&gt;Customizing my custom elements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-12g4-temp-slug-5472234"&gt;Testing!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Async loading, placeholder and a Typeahead with hyper&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0"&gt;Handling routes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b"&gt;3rd party libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mtD018rQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/74dtvrfqzhxmc11lp60r.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mtD018rQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/74dtvrfqzhxmc11lp60r.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a few common problems we deal with on a routine basis, when to brush our teeth, whether 3 day old pizza sitting on the counter is still good, and how to show users that something is happening when what is happening can’t be seen. And in a world driven by data, we often want to filter that data to only see what we want. We aren’t going to be able to help you with brushing your teeth or eating habits, but we can do something about the other problems.&lt;/p&gt;

&lt;p&gt;If you’ve been following this tutorial, you already know how powerful hyperHTML combined with custom elements can be. We’ll be able to asynchronously load data while showing placeholder information, and create a typeahead that can filter the date we receive.&lt;/p&gt;

&lt;p&gt;So let’s build a little app that solves these problems. For this part we are going to show a list of top 10 cryptocoins and the conversion to another currency. We will be using the &lt;a href="https://min-api.cryptocompare.com/"&gt;cryptocompare&lt;/a&gt; api, you can read the documentation &lt;a href="https://min-api.cryptocompare.com/documentation"&gt;here&lt;/a&gt;. You don’t need to learn the full API if you don’t want, just follow along.&lt;/p&gt;

&lt;p&gt;This is what we are going to build:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UpI1NpZx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/841/1%2AWLVWpg61DmIgZrYFL2NRCQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UpI1NpZx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/841/1%2AWLVWpg61DmIgZrYFL2NRCQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Filter on the top right to choose the rate to show.&lt;/p&gt;

&lt;p&gt;Table with the top 10 coins and the rate.&lt;/p&gt;

&lt;p&gt;Button to refresh the top 10.&lt;/p&gt;

&lt;p&gt;Let’s reuse some of our code from &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-h5b-temp-slug-4579110"&gt;part 6&lt;/a&gt;. Recall in part 6 we made a table with some random data and a few intents. We’ll build upon this table.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-13?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Typeahead
&lt;/h3&gt;

&lt;p&gt;Typeaheads are complex elements. For our current project, we’ll use a simplified typeahead. Normally we’d need a lot more code to make this element complete, but for now, a simplified version will work. Whenever the user focuses on the dropdown the list appears, you type and the list filters, click on one of the options and you get the option selected and at that moment we trigger and on change event.&lt;/p&gt;

&lt;p&gt;Be sure to review this code carefully, as we won’t go in depth about it here.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-app-01?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Notes on the typeahead code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We defined a get/set for options, to allow the user to pass options. We’re using an internal variable to store them. This helps avoid loops if we ever want to set options in our code.&lt;/li&gt;
&lt;li&gt;We’re using Bootstrap classes for styling. dropdown-menu-right will make sure the dropdown of our typeahead is visible on the screen.&lt;/li&gt;
&lt;li&gt;The open() and close() functions will set the state so when we next render, our typeahead will get the proper CSS class to show or hide. Remember, every time we call setState hyperHTML re-renders our element.&lt;/li&gt;
&lt;li&gt;We’re rendering an input that will be inside our element. This is very common thing to do with custom elements — to wrap a native element within our element. By doing this, it’s as if we are extending the native element with additional features.&lt;/li&gt;
&lt;li&gt;We don’t use (&lt;a href="https://viperhtml.js.org/hyperhtml/documentation/#essentials-7"&gt;or need!&lt;/a&gt;) partial attributes. That’s why we need to wrap the class inside a ${}.&lt;/li&gt;
&lt;li&gt;We map over any options we find and return a wire() for each one. Returning the wire() is important; otherwise, hyperHTML won’t be able to attach the DOM nodes.&lt;/li&gt;
&lt;li&gt;Events let us listen for clicks on the input and open the dropdown, and clicks on the body to close it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before we can use the typeahead, we need to import it in index.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// index.js
import "./Typeahead.js";

const input = document.querySelector("hyper-input");
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And place the custom element in the HTML:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SqYTKtXR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ARon4PkMQS-Yf-3I8iIERGg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SqYTKtXR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ARon4PkMQS-Yf-3I8iIERGg.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the basic typeahead out of the way, it’s time to fetch the list of coins. Cryptocompare FTW. We’ll do the fetch here in index.js, and pass parts of the response to our typeahead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const input = document.querySelector("hyper-input");

fetch(`https://min-api.cryptocompare.com/data/all/coinlist`)
 .then(b =&amp;gt; b.json())
 .then(data =&amp;gt; {
 input.options = data.Data;
 });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We should start options with an empty array so we don’t get undefined errors.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// typeahead.js
created() {
 this.options = [];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now let’s take a look at the table.&lt;/p&gt;
&lt;h3&gt;
  
  
  Table
&lt;/h3&gt;

&lt;p&gt;Cryptocompare has an endpoint to get a number of top coins by their total volume across all markets in the last 24 hours. We will use that one to set our table data, so let’s update index.js to do that.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch(`https://min-api.cryptocompare.com/data/top/totalvol?limit=10&amp;amp;tsym=USD`)
 .then(b =&amp;gt; b.json())
 .then(data =&amp;gt; {
 table.data = data.Data.map(coin =&amp;gt; coin.CoinInfo);
 });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The table is empty. We need to update the html to target the real attributes&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;hyper-table coin="USD"&amp;gt;
 &amp;lt;hyper-column label="ID" attribute="Id"&amp;gt;&amp;lt;/hyper-column&amp;gt;
 &amp;lt;hyper-column label="Name" attribute="FullName"&amp;gt;&amp;lt;/hyper-column&amp;gt;
 &amp;lt;hyper-column label="Rate" attribute="data" sortable="false"&amp;gt;&amp;lt;/hyper-column&amp;gt;
&amp;lt;/hyper-table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We don’t really have a data attribute, but we will see why soon.&lt;/p&gt;

&lt;p&gt;If we reload the page we see the table is empty and then all of a sudden we have the top 10 coins in the table. We should show some loading text so people know things are happening. A good place for this is inside the &lt;code&gt;&amp;lt;tbody&amp;gt;&lt;/code&gt; of our table element.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Now to get the rate, we have to make another call to the server. Just to make it cool we are going to call once for every row in the table. In real production code you probably want to make a call once for everything instead of individual calls.&lt;/p&gt;

&lt;p&gt;We added coin=”USD” to our table above. Since this is a value that can change, let’s put add an observed attribute called coin. When we start the app, it will start the hyper-input with this default value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static get observedAttributes() {
 return ["coin"];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In our &lt;code&gt;_renderCell&lt;/code&gt; function, let’s check if data is the attribute we are showing and then use the placeholder functionality of hyperHTML. This way we can show some loading text while fetch is loading, and afteward, the rate for the coin.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;There’s a lot going on in this code. We’ve primarily encountered wires that look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return wire()`&amp;lt;div class=${this.state.open}&amp;gt;&amp;lt;/div&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;However, in the above code, notice that we’re giving the wire a weak map and id: wire(item,&lt;code&gt;:col${item.Id}&lt;/code&gt;) Hyper will use this to more efficiently use and render the wires. Also, for this wire we are passing an object, instead of HTML. Note that the “any” property is a promise that returns a wire, and the “placeholder” property is a wire. Hyper will use what is in the placeholder property until the promise in any is fulfilled. Whenever fetch is done, we are o return the rate and hyper will remove the placeholder wire and update our element with the new information. Pretty cool!&lt;/p&gt;

&lt;p&gt;Success! We can see our table loading the coins then making 10 more requests to get the rate for each coin.&lt;/p&gt;
&lt;h3&gt;
  
  
  Putting it all Together
&lt;/h3&gt;

&lt;p&gt;The next step is to connect the input with the table, we will do that in index.js&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input.addEventListener("change", e =&amp;gt; {
 table.coin = input.value;
 table.render();
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Everytime our input changes, we will update the table coin with the new value and the re-render the table, which will make the rate column make new requests with the new coin and show the new data :D.&lt;/p&gt;

&lt;p&gt;Oh no, we lose the sorting whenever we refresh the data… kind of makes sense since it’s new data. To fix that, let’s move the sorting piece outside our &lt;code&gt;headerclick&lt;/code&gt; to its own function, and whenever we add new data we will just re-sort.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Alright! Lastly, for our table we will put a last-updated time in the footer. We have a date intent already, but for this we want to show the time also. Making a dateTime intent will help us with that&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Very similar to our previous one but now we are showing the time too.&lt;/p&gt;

&lt;p&gt;In the set data function, we are going to add a date so we have it for the footer&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set data() {
 this._last = Date.now()
 ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And of course the footer now looks like this&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dCS-gexj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/975/1%2ASA_cH36XcFAoxCW10iXfRw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dCS-gexj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/975/1%2ASA_cH36XcFAoxCW10iXfRw.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code so far&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-app-02?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Refresh
&lt;/h3&gt;

&lt;p&gt;Since the top 10 changes rather often, let’s add a refresh button. With this button, the table can be updated without refreshing the whole page.&lt;/p&gt;

&lt;p&gt;First, index.html, under the hyper-table add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p class="text-center"&amp;gt;&amp;lt;button class="btn btn-outline-secondary"&amp;gt;Refresh&amp;lt;/button&amp;gt;&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Then in index.js, let’s wrap the fetch call for the table in a function called update. This way we can keep calling that every time we click the refresh button. We will also call it when we load the page so that we can get initial data to display.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;And that’s it! Clicking on refresh updates the table and we can see the new timestamp in the footer.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/advanced-app-03?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I tried to focus more on the new parts, but if you need a more in-depth explanation of any part let me know in the comments and we can extend that part. Thanks for reading.&lt;/p&gt;

&lt;p&gt;One last O Rly book :D&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iNHZ6teM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/474/1%2A__l4SOkDgFZFNn6nD2J7xQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iNHZ6teM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/474/1%2A__l4SOkDgFZFNn6nD2J7xQ.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;




</description>
      <category>javascript</category>
      <category>hyperhtml</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Easy apps with hyperHTML — 7, Testing</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Tue, 04 Jun 2019 16:27:08 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-5b9g</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-5b9g</guid>
      <description>&lt;p&gt;Part 7 written by Trevor Ganus, &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
  
    .ltag__user__id__60874 .follow-action-button {
      background-color: #353638 !important;
      color: #FFFFFF !important;
      border-color: #353638 !important;
    }
  
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MvWCfXka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--yF4B1j7T--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/60874/62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://twitter.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="twitter logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--oEHrSmvE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-logo.svg"&gt;pinguxx
        &lt;/a&gt;
        &lt;a href="https://github.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;pinguxx
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
  
    .ltag__user__id__171460 .follow-action-button {
      background-color: #093656 !important;
      color: #FFFFFF !important;
      border-color: #093656 !important;
    }
  
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r4dfAuX5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--NSzkAUjv--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/171460/77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://github.com/paritho" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;paritho
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;Introduction, wire/bind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;Events and components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;Moar about components and simple state management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;Wire types and custom definitions (intents)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-5hdl-temp-slug-7285698"&gt;Custom elements with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-h5b-temp-slug-4579110"&gt;Customizing my custom elements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testing!&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96"&gt;Async loading, placeholder and a Typeahead with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0"&gt;Handling routes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b"&gt;3rd party libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KJln3FZk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qedmndmqtwvnww2mjr1f.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KJln3FZk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qedmndmqtwvnww2mjr1f.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m not a big fan of having 100% code coverage, etc, etc, etc. But if we are writing components, they probably need to be tested as much as possible. We won't go super deep into testing, but we do want to show a few ways you can test your components and elements.&lt;/p&gt;

&lt;p&gt;A small caveat before we begin: this post isn’t intended to cover everything you need to know about unit testing. Many other tutorials can teach you the basics of how to write code that tests well. Our goal is to show you how to use specific testing tools, with the understanding that you have a basic understanding of unit tests in general. With that out of the way, let’s get started!&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter Tressa
&lt;/h3&gt;

&lt;p&gt;Yup, YAAT — Yet Another Andrea Tool. Tressa is a very simple testing utility that we are going to use to test our stuff. It gives us the ability to do synchronized tests and asynchronous tests. It also comes with a basic assert function. Tressa requires consolemd, a module that lets us print using markdown to the console, which is pretty neat. Let’s see an example:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-testing-01?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : we have to load tressa and consolemd with unpkg because for some reason stackblitz never finds echomd even if installed. Open the real console to see errors, the inner console from stackblitz doesn’t show them for some reason.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's dissect the code a bit to understand all the pieces&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tressa.title&lt;/code&gt; Starts a “section” of tests, by default title adds (“#”) for you&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tressa.end&lt;/code&gt; Ends the section of tests and returns the time spent on them&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tressa and tressa.assert&lt;/code&gt; This where you put your assertions with an optional comment as a second argument. You can use either one, there is no difference between them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tressa.log&lt;/code&gt; console out with markdown, useful to separate parts of your tests&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tressa.async&lt;/code&gt; Need to wait for an async operation? Use this wrapper. It returns a promise to test those cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can see that tressa makes it very easy to test our code. Hopefully, you remember our table created with only &lt;code&gt;hyper.Component&lt;/code&gt;. If not, here’s a quick refresh:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-7?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Open the real console to see errors, the inner console from stackblitz doesn’t show them for some reason.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Components
&lt;/h3&gt;

&lt;p&gt;First let’s load consolemd and tressa. Then, let’s add a test for the footer component in our table. This component doesn’t really do much, so testing should be straightforward. Open the console to see the test results. If you are doing async tests, don’t forget to call the &lt;code&gt;done()&lt;/code&gt; callback when your test is finished.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-testing-02?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Cool, let’s move on to the header component. For this one, let’s see if the &lt;code&gt;&amp;lt;thead&amp;gt;&lt;/code&gt; is getting icons when we pass the sorted property&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s also test the clicking on an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tag:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And now, all the code together:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-testing-03?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;So far, our tests have been on components separated from the DOM. We instantiate the elements with the new keyword. Let’s wrap up the table testing with a test directly on the component already rendered:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-testing-04?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We don’t need to write all the tests in this asynchronous way, but I like it since it separates sections of our tests better. Being familiar with the asynchronous tests now will help us later, when we write more complex tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a8VgZCHC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1000/1%2A-DMTBsco27Ad3zJ8209N5Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a8VgZCHC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1000/1%2A-DMTBsco27Ad3zJ8209N5Q.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Intents
&lt;/h3&gt;

&lt;p&gt;In our component project, we also have a couple of intents — one for icons and one for dates. Let’s test those now. For now, let’s remove the component testing so it’s easier to focus on the intents.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Well… we found our first bug. If we pass “a”, which is an icon that doesn’t exist in &lt;a href="https://octicons.github.com/"&gt;Octicons&lt;/a&gt;, we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeError: Cannot read property ‘toSVG’ of undefined
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let’s fix the intent:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Sweet, our test passes with the updated code. Now let’s test the date intent:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Err… that last test shows batman! &lt;code&gt;NaN/NaN/NaN&lt;/code&gt;, let’s fix that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (!isNaN(newdate.getTime()) &amp;amp;&amp;amp; typeof newdate.getMonth === ‘function’)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Yay! Let’s see the result:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-testing-05?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ivq0UuH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/512/1%2ABs54g93GAySCBSunqJdubg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ivq0UuH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/512/1%2ABs54g93GAySCBSunqJdubg.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Custom elements
&lt;/h3&gt;

&lt;p&gt;This is our table as a custom element:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-13?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Since we are already using the functions of the table, let’s rewrite those as tests. But first let’s add some utilities and then put all the tests in a single file.&lt;/p&gt;

&lt;p&gt;Let’s see if we are actually loading a table first:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;It’s there, cool! Notice we get the same result from &lt;code&gt;tressa()&lt;/code&gt; as when we were using &lt;code&gt;tressa.assert()&lt;/code&gt; in our previous tests. Now let’s test data:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;There are a couple of things we want to look at here. First, data will make a row appear, but since it doesn’t have any real data everything will be “-”… except date… lets update the intent to fix that with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let formatted = ‘-’,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Second, data is more real and we see that we have data in our rows and the footer is updated.&lt;/p&gt;

&lt;p&gt;Now let’s test the column functions: add/remove/update&lt;/p&gt;
&lt;h3&gt;
  
  
  Add
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Update
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Last but not least, sorting:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s see everything working together:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-testing-06?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Coverage
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HsJN9U-Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/320/1%2Ac3fZfe4bPDmWbXpf2rc-MQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HsJN9U-Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/320/1%2Ac3fZfe4bPDmWbXpf2rc-MQ.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We tested our code, but what if we want to see how much was tested? For this, Istanbul is our friend. We can’t run Istanbul from stackblitz (that I’m aware of), but let’s create a project in github to run it, and that will generate a coverage report.&lt;/p&gt;

&lt;p&gt;For this kind of test we’ll need to have &lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; and &lt;a href="https://www.npmjs.com/"&gt;npm&lt;/a&gt;installed. If you’re not familiar with these tools, &lt;a href="https://www.tutorialspoint.com/nodejs/nodejs_npm.htm"&gt;here is a great place to start&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, we need to change a couple of things. Code-wise we need to remove the tests from index.js and created a file called test.js (clever right?). Then, we need to remove all the imports except intents and table. With those changes, our index.js file looks like:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We also will need to setup the test environment, since we are not going to use a browser for our tests. Instead, we are going to use &lt;a href="https://github.com/WebReflection/basicHTML"&gt;basicHTML&lt;/a&gt;. BasicHTML is a lightweight, dumb, and simple implementation of the HTML standard” — and yes it’s a YAAT.&lt;/p&gt;

&lt;p&gt;So our start of the test file looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We bring tressa, then basicHTML, and we set it up. We are also bringing sizzle so we can make complex queries (sizzle is the selector engine used by JQuery so it’s a powerful tool). Then we load hyperHTML, and finally our tests with index.js.&lt;/p&gt;

&lt;p&gt;Then, we setup our fake browser by making it ready and DOMContentLoaded. We can then add our table — just like regular HTML — by using a wire. That’s it! Let’s grab our table and run the same test we wrote previously.&lt;/p&gt;

&lt;p&gt;Now, to run all of this we need a bunch more of dev dependencies. Add this to the package.json file and &lt;code&gt;npm i&lt;/code&gt; away&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The first part is just our dependencies for the tests. We added a script for running our test — nyc is the istanbul cli. Lastly, we setup nyc so it loads babel to transpile our code, and we add a couple of handy reporters. The HTML reporter will make it so we can look at a pretty web page.&lt;/p&gt;

&lt;p&gt;Since we don’t need the classes to be transpiled lets add a .babelrc to customize the behavior.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;When testing we use Istanbul and we target firefox 52… why 52?? IDK, sounds like a good number and it was the old ESR :D.&lt;/p&gt;

&lt;p&gt;aaaand then fire up a console terminal, navigate to the folder with your package.json, and enter the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Hopefully you will see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QSOovMJ---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/598/1%2ABF8olzLf8E5Zlb5qH072ig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QSOovMJ---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/598/1%2ABF8olzLf8E5Zlb5qH072ig.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the coverage folder and open index.html to see the report… almost 100%… mm what are we missing? Take a peek at the Table.js file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (ElOrObj.nodeName === "HYPER-COLUMN") {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Apparently basicHTML is case sensitive. No problem, it’s an easy fix. Let’s do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (ElOrObj.nodeName &amp;amp;&amp;amp; ElOrObj.nodeName.toLowerCase() === "hyper-column") {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;npm test again, open the report… 100%&lt;/p&gt;

&lt;p&gt;Yay! We did it! You can clone the full project here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/pinguxx/easyapps-7-test1"&gt;pinguxx/easyapps-7-test1&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration tests
&lt;/h3&gt;

&lt;p&gt;For integration testing, I really like &lt;a href="https://www.cypress.io/"&gt;cypress&lt;/a&gt;. It’s very easy to use and powerful. It lets us create unit, end-to-end, and integration tests. Cypress also gives you the ability to see the state of your web page/app at each stage of the tests.&lt;/p&gt;

&lt;p&gt;With integration testing, we are testing the page directly, so we need to add some things to make that happen. Time does not permit me to explain everything for this, but if you want a more detailed explanation, let me know and I can create a post detailing the process.&lt;/p&gt;

&lt;p&gt;The tl;dr; goes like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add cypress/rollup/babel and plugins to package.json&lt;/li&gt;
&lt;li&gt;Add test/build scripts in package.json&lt;/li&gt;
&lt;li&gt;run cypress for the first time&lt;/li&gt;
&lt;li&gt;build (babel/bundle) index.js with all the modules used&lt;/li&gt;
&lt;li&gt;start a local server http-server -p 8081&lt;/li&gt;
&lt;li&gt;create a new integration test, table_spec.js is what I called mine&lt;/li&gt;
&lt;li&gt;replicate tressa test and/or add more&lt;/li&gt;
&lt;li&gt;profit!!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4hIFa-Ja--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Akqt4GZ6dpT_aPY3IKNONrw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4hIFa-Ja--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2Akqt4GZ6dpT_aPY3IKNONrw.png" alt=""&gt;&lt;/a&gt;Test passed :D&lt;/p&gt;

&lt;p&gt;For more information, check out the &lt;a href="https://docs.cypress.io/guides/overview/why-cypress.html#In-a-nutshell"&gt;cypress docs&lt;/a&gt;. You can also clone and run the tests yourself with this project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/pinguxx/easyapps-7-test2"&gt;pinguxx/easyapps-7-test2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m not the best at testing, but this shows a couple of ways to test our components and elements.&lt;/p&gt;

&lt;p&gt;As always, let us know your feedback and what else you want to see in this series. Thanks for reading!&lt;/p&gt;




</description>
      <category>hyperhtml</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Easy apps with hyperHTML — 6, Customizing my custom elements</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Mon, 03 Jun 2019 17:52:19 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-1e73</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-1e73</guid>
      <description>&lt;p&gt;Part 6 written by Trevor Ganus, &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
  
    .ltag__user__id__60874 .follow-action-button {
      background-color: #353638 !important;
      color: #FFFFFF !important;
      border-color: #353638 !important;
    }
  
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MvWCfXka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--yF4B1j7T--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/60874/62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://twitter.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="twitter logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--oEHrSmvE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-logo.svg"&gt;pinguxx
        &lt;/a&gt;
        &lt;a href="https://github.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;pinguxx
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
  
    .ltag__user__id__171460 .follow-action-button {
      background-color: #093656 !important;
      color: #FFFFFF !important;
      border-color: #093656 !important;
    }
  
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r4dfAuX5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--NSzkAUjv--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/171460/77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://github.com/paritho" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;paritho
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;Introduction, wire/bind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;Events and components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;Moar about components and simple state management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;Wire types and custom definitions (intents)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-5hdl-temp-slug-7285698"&gt;Custom elements with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Customizing my custom elements&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-5b9g"&gt;Testing!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96"&gt;Async loading, placeholder and a Typeahead with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0"&gt;Handling routes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b"&gt;3rd party libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c2PbCaCB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/firfj2mwfpzudmvf3k58.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c2PbCaCB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/firfj2mwfpzudmvf3k58.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Recap
&lt;/h3&gt;

&lt;p&gt;In parts 1–5, we talked about the basics of hyperHTML. We also learned about an amazing feature called hyper.Component. We dove into “intents ” that let us extend hyperHTML and simplify our templates. While learning all this we created a simple table:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-7?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Finally, we learned the basics of custom elements and a nice little utility called hyperHTML-Element, which gives us some of the &lt;code&gt;hyper.Component&lt;/code&gt; features out of the box, and so much more.&lt;/p&gt;

&lt;p&gt;In part 6, we’re going to discover how we can convert our table from a component to a custom element. We’ll also see how easy it is to add functionality to our custom element, extending it to be even more useful. Using custom elements makes it so easy to reuse our code, a baby could do it — if the &lt;a href="https://www.amazon.com/HTML-Babies-Code-Sterling-Childrens/dp/1454921552"&gt;baby knew HTML&lt;/a&gt;, and &lt;a href="https://www.amazon.com/Javascript-Babies-Code-Sterling-Childrens/dp/1454921579"&gt;JavaScript&lt;/a&gt;, of course. Also, once we have a custom element, we don’t need hyperHTML anywhere else in our app unless we want it. This makes the custom elements plug-and-play with any framework. When was the last time a React component could say that?&lt;/p&gt;

&lt;h3&gt;
  
  
  Columns
&lt;/h3&gt;

&lt;p&gt;Let’s start thinking about the elements of the table: header, footer and body. For our case, header and footer are the important parts. We will generate the footer based on the data just like before.&lt;/p&gt;

&lt;p&gt;Let’s start with a custom element for the columns. This element will contain the information necessary to render:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the label (for the header)&lt;/li&gt;
&lt;li&gt;the attribute used for this column (from the data)&lt;/li&gt;
&lt;li&gt;if it’s sortable or not&lt;/li&gt;
&lt;li&gt;the type of data to display&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-07?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Simple right? We don’t even render anything, all the heavy lifting will be in the table itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Table
&lt;/h3&gt;

&lt;p&gt;Now let’s generate a custom element with a simple table.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-08?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Let’s first add a hyper-column to our HTML&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Then, we need to update our created function to read the columns and store them in an array that we can reuse later:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;(used &lt;code&gt;[].slice.call&lt;/code&gt; instead of &lt;code&gt;[…this.querySelectorAll(“hyper-column”)]&lt;/code&gt; because of an error using stackblitz)&lt;/p&gt;

&lt;p&gt;And lastly, let’s update our template to use the columns.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Well cool. But we are not really using data from anywhere… let’s fix that. We’ll add a data property.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We now need to update our &lt;code&gt;&amp;lt;tbody&amp;gt;&lt;/code&gt; part of the template to show one row for each item in the data.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;(if &lt;code&gt;wire(column, `col${item.id}`)&lt;/code&gt; looks unfamiliar to you, review &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;part 4&lt;/a&gt;!)&lt;/p&gt;

&lt;p&gt;Of course, we still need to pass data to the table. The index file is where we’ll do that.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s see our full code so far:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-09?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;To finish off the table, we need to add the rest of the columns. Notice, this is very similar to what we’ve done in previous parts of this tutorial!&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Intents
&lt;/h3&gt;

&lt;p&gt;Recall intents from &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;part 4&lt;/a&gt;? Let’s use intents to display icons and dates correctly. We happen to like the &lt;a href="https://octicons.github.com/"&gt;octicon&lt;/a&gt; library of icons, but you can feel free to bring your own icon set.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Then extract the rendering of the &lt;code&gt;&amp;lt;td&amp;gt;&lt;/code&gt;’s and &lt;code&gt;&amp;lt;th&amp;gt;&lt;/code&gt;’s for easier reading.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;(Note that, for user-provided values, you should be sure to use the ‘text’ type. Otherwise, use of ‘html’ could lead to potential HTML injection issues. Normally, hyperHTML will escape HTML used in expressions &lt;code&gt;${...}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We are using state so let’s make sure we have a defaultState set:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And again update our template&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Much easier to follow :D.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-10?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  State &amp;amp; Events
&lt;/h3&gt;

&lt;p&gt;We need to be able to sort the data when a user clicks on the table header. Let’s add &lt;code&gt;onclick="${this}" data-call="headerClick"&lt;/code&gt; to our a tags so we can do this. We will also need to add the &lt;code&gt;headerClick&lt;/code&gt; function to handle the event.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Remember calling &lt;code&gt;setState&lt;/code&gt; will call &lt;code&gt;render()&lt;/code&gt;, so we don’t need to explicitly call &lt;code&gt;render()&lt;/code&gt; here. Let’s see our table with the sorting and icons working.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-11?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Footer
&lt;/h3&gt;

&lt;p&gt;Then at the bottom of the table, we will add our footer.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Nothing fancy here. Aaannddd we are done… or at least we replicated the component we had with custom elements. This is no small thing. Now, we can just use &lt;code&gt;&amp;lt;hyper-table&amp;gt;&lt;/code&gt; with some &lt;code&gt;&amp;lt;hyper-column&amp;gt;&lt;/code&gt; inside and you have a simple yet functional table.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-12?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--smSc8jwX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/1%2AUrLtjrYjonasE97oiL6f8A.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--smSc8jwX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/1%2AUrLtjrYjonasE97oiL6f8A.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Customization
&lt;/h3&gt;

&lt;p&gt;Every good table should be able to add/update/remove columns, right? Glad you asked! Let’s add some functions to our table that will allow us to do just that.&lt;/p&gt;

&lt;p&gt;First let’s add to our column element a new attribute called name. This will be used to update/remove columns. If no name is passed we’ll just use the attribute.&lt;/p&gt;

&lt;h4&gt;
  
  
  addColumn
&lt;/h4&gt;

&lt;p&gt;We will let the developer add a column by passing a new &lt;code&gt;&amp;lt;hyper-column&amp;gt;&lt;/code&gt;. We’ll also allow an object to be passed with the attributes needed. This will update our columns array.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  removeColumn
&lt;/h4&gt;

&lt;p&gt;Based on the newly added name to the column, we can easily remove columns from the table. In theory we could use index instead of name, but I wanted to show that we can do either with the elements.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  updateColumn
&lt;/h4&gt;

&lt;p&gt;Again using the name attribute, we can update the column details.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s see how it looks:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-13?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Well, that was easy, and we enhanced our table with very useful functionality!.&lt;/p&gt;

&lt;p&gt;Now you are a custom element/hyperHTML master :D. Or, at least you can start creating your own elements! In the next part we are going to add testing to our table element and maybe add the ability to filter the table display. Please send us your feedback to improve this tutorial.&lt;/p&gt;




</description>
      <category>hyperhtml</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Easy apps with hyperHTML — 5, Custom elements</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Fri, 31 May 2019 14:50:46 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-13hc</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-13hc</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/easy-apps-with-hyperhtml/aplicaciones-f%C3%A1ciles-con-hyperhtml-5-402970bf26b4" rel="noopener noreferrer"&gt;Version en español&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part 5 written by &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F60874%2F62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171460%2F77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;Introduction, wire/bind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;Events and components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;Moar about components and simple state management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;Wire types and custom definitions (intents)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom elements with hyper&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-1e73"&gt;Customizing my custom elements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-5b9g"&gt;Testing!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96"&gt;Async loading, placeholder and a Typeahead with hyper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0"&gt;Handling routes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b"&gt;3rd party libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Frgz0njhgpaofeptcv3ra.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Frgz0njhgpaofeptcv3ra.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  My very own tag
&lt;/h3&gt;

&lt;p&gt;If you’ve been developing web pages or apps for any amount of time, chances are you’ve seen custom components or HTML tags, especially if you’ve worked with one of the newer JavaScript frameworks. Whatever the name, these components usually all have a similar goal: encapsulate functions and logic into re-usable chunks of code. After a lot of discussion and development by the community, we finally brought these ideas under the canopy of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" rel="noopener noreferrer"&gt;Web Components&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Web Components is a suite of different technologies allowing you to create reusable custom elements — with their functionality encapsulated away from the rest of your code — and utilize them in your web apps. — MDN&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to achieve this, the specification addresses the following technologies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Custom elements&lt;/strong&gt; : A set of JavaScript APIs that lets you define the logic of the element. You can create a function like open() and then you can just call that function from the element document.querySelector(‘custom-dialog’).open().&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadow Dom&lt;/strong&gt; : Utilizing the shadow DOM enables you to use other HTML elements inside your custom element, even other custom elements! Whatever code is inside the custom element with shadow DOM enabled will be rendered and styled separately. This can be both a bug and a feature, depending on your use case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML templates&lt;/strong&gt; : Two tags &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; let you write HTML inside the custom element, but they are not rendered or displayed until you activate them. &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; can also be re-used for other things.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not every one of these are ready to use in all browsers, and certain aspects are harder to polyfill than others, but we are getting close.&lt;/p&gt;

&lt;p&gt;For now we will concentrate on the basics of custom elements, but at the end we’ll show you how to use the shadow DOM. We’ll also see that hyperHTML can create highly efficient templates. We’ll be able to do everything with hyperHTML that &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; can, except for native use of &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &amp;lt;custom-element awesome=”true”&amp;gt;
&lt;/h4&gt;

&lt;p&gt;To get started making custom elements, we need need 3 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A browser that supports custom elements, or a polyfill. We recommend using &lt;a href="https://github.com/WebReflection/document-register-element" rel="noopener noreferrer"&gt;document-register-element&lt;/a&gt;. This polyfill has been used in production for a while by projects like amp. Alternatively, Google also has a polyfill worth checking out.&lt;/li&gt;
&lt;li&gt;A class that extends the HTMLElement object. This class will contain all the logic for our element. We can also extend from a normal HTML element.&lt;/li&gt;
&lt;li&gt;Finally, we will need to “define” the element. This is how we’ll register our element in the browser, and give it a name.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In 2 above, we mentioned that there are two ways to extend your custom element class, either by extending HTMLElement, or a build-in HTML tag like span. When we extend HTMLElement, our custom element will be autonomous. However, extending built-ins is a bit controversial, and while the specs describe how to do it, not all browsers are on board. We will see how do both, but for our use case in this blog we are only going to extend from HTMLElement.&lt;/p&gt;

&lt;p&gt;Enough jibber-jabber, show me the code!&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-01?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;(A tiny, huge thing in the index.html, since Stackblitz is automagically transpiling our code, we need to include the es5-adapter)&lt;/p&gt;

&lt;p&gt;Lets dissect the code a bit:&lt;/p&gt;

&lt;p&gt;First we name our class and extend HTMLElement. This will be an autonomous element. Then, we have a function called &lt;code&gt;connectedCallback()&lt;/code&gt;. &lt;code&gt;connectedCallback()&lt;/code&gt; will be called after the browser has appended the custom element to the document. We’ll talk more about the custom element lifecycle later on. Inside &lt;code&gt;connectedCallback()&lt;/code&gt; we are just adding text to our custom element.&lt;/p&gt;

&lt;p&gt;On line 9 we are defining our element name. Whatever name you choose, you must include a hyphen. In our case, to use this element in HTML we will use the tag &lt;code&gt;&amp;lt;custom-element&amp;gt;&amp;lt;/custom-element&amp;gt;&lt;/code&gt;. The define function also takes a second parameter which is the class describing the element.&lt;/p&gt;

&lt;p&gt;Internally, the browser keeps a registry of all the custom elements we define. One of the things we can do with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry" rel="noopener noreferrer"&gt;CustomElementRegistry&lt;/a&gt; is wait for the elements to be defined. However, we can do a lot of other things. So be sure to take a look at the docs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F325%2F1%2AUf6yUZuRXXKeYHFL8jabYg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F325%2F1%2AUf6yUZuRXXKeYHFL8jabYg.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just for funz lets see how to extend a built-in:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-02?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Life cycle
&lt;/h4&gt;

&lt;p&gt;Besides &lt;code&gt;connectedCallback()&lt;/code&gt; there are other lifecycle hooks we can use. Let’s see what they do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;connectedCallback&lt;/strong&gt; : called when your element is connected to the document DOM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;disconnectedCallback&lt;/strong&gt; : called when your element is detached from the DOM. You will be able to react to that disconnection in this function.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;adoptedCallback&lt;/strong&gt; : is called when you move the element to a new page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;attributeChangedCallback&lt;/strong&gt; : this is called whenever attributes that you are monitoring change. Not every attribute on your custom element will automatically be monitored. To pick which attributes are, you will have to add another function:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static get observedAttributes() {return ['attr1', 'attr2']; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s see these functions in action in our custom-element:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-03?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This is cool! We’re well on our way to having a powerful new element. But what about templating? With hyperHTML, we can render whatever we want inside the element and boom, custom elements with all the power of hyperHTML :D&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F220%2F1%2AoQV46mV2KLACQJMUNZ6WjA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F220%2F1%2AoQV46mV2KLACQJMUNZ6WjA.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s make a few changes. Of course, we first need to load hyperHTML. Then we will bind to the current element with &lt;code&gt;this.html = bind(this);&lt;/code&gt; We also need a &lt;code&gt;render()&lt;/code&gt; function which will be charged with rendering the template. And finally, we need to update our &lt;code&gt;attributeChangedCallback()&lt;/code&gt; to change new attribute values to actual properties:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-04?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter hyperHTML-element
&lt;/h3&gt;

&lt;p&gt;There is a lot more to learn about custom elements, but fortunately the master &lt;a href="https://medium.com/u/cc83da4b8256" rel="noopener noreferrer"&gt;Andrea Giammarchi&lt;/a&gt; created another utility that abstracts much of the custom element API. It’s called &lt;a href="https://github.com/WebReflection/hyperHTML-element" rel="noopener noreferrer"&gt;hyperHTML-element&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a class that you can extend instead of the HTMLElement, and it gives you a few new functions and properties.&lt;/p&gt;

&lt;h4&gt;
  
  
  Functions
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Besides the regular &lt;code&gt;observedAttributes&lt;/code&gt; we now also have &lt;code&gt;booleanAttributes&lt;/code&gt;. This is where we’ll want to put the attributes that don’t need an actual value. For example, &lt;code&gt;&amp;lt;custom-element required&amp;gt;&lt;/code&gt;. “Required” either exists or it doesn’t, so it is a great candidate for being a boolean attribute.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;observedAttributes&lt;/code&gt; and &lt;code&gt;booleanAttributes&lt;/code&gt; both will also define getters and setters for every attribute observed. This means we no longer need to do &lt;code&gt;this[name] = newValue&lt;/code&gt; inside attributeChangedCallback.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;created&lt;/code&gt;. This is a new callback that will be invoked right before &lt;code&gt;connectedCallback&lt;/code&gt; or &lt;code&gt;attributeChangedCallback&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;defaultState()&lt;/code&gt;. Whenever you use this.state, the &lt;code&gt;defaultState()&lt;/code&gt; function returns an object that becomes, you guessed it, the default state.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setState&lt;/code&gt;. Updates the state object (you don’t need to define &lt;code&gt;defaultState&lt;/code&gt; to use &lt;code&gt;setState&lt;/code&gt;). &lt;code&gt;setState&lt;/code&gt; includes a little bonus: it will call &lt;code&gt;render()&lt;/code&gt; for you, so your element is automatically updated when you change its state!&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;render()&lt;/code&gt;. This function should return the HTML you want to display inside your custom element.&lt;/li&gt;
&lt;li&gt;Event handlers. In your template, we can now pass ‘this’ to our event handlers: &lt;code&gt;&amp;lt;div onclick=${this}&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;. If we then define an &lt;code&gt;onclick&lt;/code&gt; function inside the element, it will get called with the proper context. You can also use data-call to call any function: &lt;code&gt;data-call=onAnyEvent onclick=${this}…&lt;/code&gt; in this case &lt;code&gt;onAnyEvent&lt;/code&gt; will be called when a user clicks. Even more cool, custom events are super easy: &lt;code&gt;onMyCustomEvent=${this}&lt;/code&gt; and you define a &lt;code&gt;onMyCustomEvent(e)&lt;/code&gt; function, done!&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;define()&lt;/code&gt;. This static method is just a helper. Instead of using &lt;code&gt;customElements.define&lt;/code&gt; you use this one &lt;code&gt;MyElement.define('my-element')&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;All the hyperHTML functions, &lt;code&gt;bind&lt;/code&gt;, &lt;code&gt;component&lt;/code&gt; and &lt;code&gt;wire&lt;/code&gt;. The only hyper function we don’t get is define for intents, since we’re already using it to register the element. To define intents you will use &lt;code&gt;HyperHTMLElement.intent(…)&lt;/code&gt;. We looked at intents in another &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;part 4&lt;/a&gt; of this blog, so be sure to brush up on them if you need to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Observant readers will notice some of these functions are used in &lt;code&gt;hyper.Component&lt;/code&gt;. Hopefully you are familiar with some of them now :D&lt;/p&gt;

&lt;h4&gt;
  
  
  Properties
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;this.html&lt;/code&gt;. In our example above we did &lt;code&gt;this.html = bind(this);&lt;/code&gt; in the &lt;code&gt;constructor&lt;/code&gt;. With hyperHTML-elemet we now can use &lt;code&gt;this.html&lt;/code&gt; directly.&lt;/li&gt;
&lt;li&gt;state. State is an object that holds the…er…state of the element. It’s empty by default, or it will hold whatever object is returned by &lt;code&gt;defaultState&lt;/code&gt;, if you’ve defined that function.&lt;/li&gt;
&lt;li&gt;As mention before, every attribute in &lt;code&gt;observedAttributes&lt;/code&gt; and &lt;code&gt;booleanAttributes&lt;/code&gt; will have its getter and setter, so you can use &lt;code&gt;this.attr&lt;/code&gt; and the value will reflect the attribute. For example, &lt;code&gt;&amp;lt;my-element parent="your mom"/&amp;gt;&lt;/code&gt;, using &lt;code&gt;this.parent&lt;/code&gt; will give you the value, “your mom.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sweet! Let’s update our previous element to use all of these new features:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-05?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F500%2F1%2ATTLxQoccKUZvMDwsgPJO1A.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F500%2F1%2ATTLxQoccKUZvMDwsgPJO1A.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What about the shadow DOM?… oh yeah, it’s super easy:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/intermediate-ce-06?ctl=1" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Check line 8 &lt;code&gt;this.attachShadow({mode: ‘open’});&lt;/code&gt;, if you inspect the element you’ll see that the shadow DOM is there!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F466%2F1%2AVtc8-XOraDyHOO5Ar741Rg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F466%2F1%2AVtc8-XOraDyHOO5Ar741Rg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is more to learn about custom elements and web components in general. In the next part we will write some custom logic and update our table from &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;part 4&lt;/a&gt; to be a custom element. And as always, feedback is welcome!&lt;/p&gt;




</description>
      <category>javascript</category>
      <category>hyperhtml</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Easy apps with hyperHTML — 4, wire types and intents</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Thu, 30 May 2019 16:38:44 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/easy-apps-with-hyperhtml/aplicaciones-f%C3%A1ciles-con-hyperhtml-4-785f5d35f895" rel="noopener noreferrer"&gt;Version en español&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part 4 written by &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F60874%2F62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F171460%2F77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;Introduction, wire/bind&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;Events and components&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;Moar about components and simple state management&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Wire types and custom definitions (intents)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-13hc"&gt;Custom elements with hyper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-1e73"&gt;Customizing my custom elements&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-5b9g"&gt;Testing!&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96"&gt;Async loading, placeholder and a Typeahead with hyper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0"&gt;Handling routes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b"&gt;3rd party libraries&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In previous parts of this tutorial, we’ve seen how to use components with hyperHTML. We built a simple table that could sort, but now it’s time to look at some additional features hyperHTML brings us. The feature we’ll look at next is the ability to customize wire(). With a custom wire() function, we’ll be able to transform our templates, or load parts of them asynchronously. Before we dive into this, let’s explore the standard wire() function a little more.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Built-in Types&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;HyperHTML wire() comes with two built-in types. Its default is html, but hyperHTML also supports svg. As we’ve seen, using the html type requires no additional work on our part. However, if we want to wire an svg node, we need to explicitly say so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hyperHTML.wire(data, 'svg')`&amp;lt;rect width=${data.width} height=${data.height} /&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second parameter passed to wire is the type. Let’s see the example running:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/wire-types-svg?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Recall all the way back to &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;part 1&lt;/a&gt;. In our clock example, we used wire() two ways. First, we used it without a reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hyperHTML.wire()`…`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But then we also used it by passing an object to the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hyperHTML.wire(user)`…`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that first example we mentioned that the object passed to wire() will not be updated each time it renders. This is because by passing it to wire() we are creating a a relationship between wire and the contents of the object. This relationship does more than just speed up renders, we can also re-use this object in different places, with different templates. We might then give this object an id for each place we want to use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hyperHTML.wire(user, ':address')`…`
hyperHTML.wire(user, ':profile')`…`
hyperHTML.wire(user, ':login')`…`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/wire-types-user?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We can also specify a type alongside the id:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hyperHTML.wire(user, 'svg:avatar')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Content Values
&lt;/h4&gt;

&lt;p&gt;We also talked a bit about the different content values in &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;part 1&lt;/a&gt;. Let’s dive deeper into them now.&lt;/p&gt;

&lt;p&gt;Think about template literals. Inside a template literal we use ${…} to evaluate expressions. Whatever expression you pass into the ${…} will be added to your template depending on it’s evaluated type. For example, hyperHTML is injection-safe by default since passing strings will be injected to the template as &lt;code&gt;textContent.&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p&amp;gt;Hola ${'&amp;lt;script src="http://badguy.com"&amp;gt;&amp;lt;/script&amp;gt;'}&amp;lt;/p&amp;gt; // whew, safe!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you can also force it to be text. In order to do that, you have to pass an object to hyperHTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p&amp;gt;Hola ${{text: 'Mundo'}}&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And yes, if you pass a node it will be appended:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p&amp;gt;Hola ${node}&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or you can force it by passing an object, like above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p&amp;gt;Hola ${{html: '&amp;lt;strong&amp;gt;Mundo&amp;lt;/strong&amp;gt;'}}&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can even pass a promise! If you do pass a promise, then whenever the promise is resolved it will be resolved to any of the understood types. There is also a type, any. Any usually takes a promise, but can take any other type as well, and hyperHTML will try to match it.&lt;/p&gt;

&lt;p&gt;See them in action:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/wire-values?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;But wait, that’s not all! You can also pass arrays! The only thing to keep in mind is the items in the array &lt;strong&gt;&lt;em&gt;must&lt;/em&gt;&lt;/strong&gt; be of the same type: strings or numbers or nodes, or even a list of promises. You’ll get unexpected results if your array is populated with different types.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/wire-array?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We typically use promises when we don’t have data now, but are promised to have in the future. HyperHTML provides a placeholder that displays while the data is loading. Let’s see an example.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/wire-placeholder?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Attributes
&lt;/h4&gt;

&lt;p&gt;Element attributes can be regular attributes, booleans, or events. If you’re coming to hyperHTML from another framework, you might be expecting to use partial attributes, but &lt;a href="https://viperhtml.js.org/hyperhtml/documentation/#essentials-7" rel="noopener noreferrer"&gt;you don’t actually need them&lt;/a&gt;. There are two more attribute types we need to talk about — style and data. These attributes will help us easily build interfaces.&lt;/p&gt;

&lt;p&gt;The style attribute can take a string like any other attribute, or you can also pass an object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wire(ref)`&amp;lt;p style=${{fontSize: 32}}&amp;gt;${'BIG CONTENT'}&amp;lt;/p&amp;gt;`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data attribute lets you pass raw JavaScript data to an element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wire(ref)`&amp;lt;p data=${user} /&amp;gt;`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s see them in action&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/wire-attributes?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h3&gt;
  
  
  Custom types
&lt;/h3&gt;

&lt;p&gt;We can tap into that object functionality and create our custom render parts. And depending on the name, it will be interpreted as an attribute (if it has ‘-’), or as a new intent.&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom intent
&lt;/h4&gt;

&lt;p&gt;To define a new type, we will use &lt;code&gt;hyperHTML.define()&lt;/code&gt; . Convenient, right? Define() takes two parameters, a string name and a callback.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;define(intentName, callback)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The callback receives any interpolated data as parameters, and returns data that we’ll use in the display. The callback can return any of the known data types.&lt;/p&gt;

&lt;p&gt;For example, let’s define an intent for dates. Whenever we receive a date, we will return a nicely formatted date. Let’s also use an asynchronous intent:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/wire-custom?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;HyperHTML will first try to match on any known intents like html, text or any. If it cannot find a match, it will try with the ones it has in its registry, that is, the ones defined with &lt;code&gt;hyperHTML.define()&lt;/code&gt;. If hyper finds it there, it will use your custom intent.&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom attributes
&lt;/h4&gt;

&lt;p&gt;As mentioned before, if you define the intent with a ‘-’ in the name, it will be treated as an attribute. This means we can add any custom attribute to any element.&lt;/p&gt;

&lt;p&gt;Whoah. Seriously?&lt;/p&gt;

&lt;p&gt;Yep, you bet.&lt;/p&gt;

&lt;p&gt;In our next example, the callback will receive the node element and whatever value passed to the attribute. If you return something, it will be used as the value for the attribute. Be sure to note, that to make the custom attribute work you must use &lt;code&gt;${…}&lt;/code&gt; for the attribute value.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/wire-custom-attribute?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;p&gt;With what we now know, let’s update our table from &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;part 3&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-6?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We’ll add an svg icon, so we know what column is currently sorted and if it’s ascending or descending. Let’s also update our data array with more accurate user information, as well as a date so we can put our date intent to good use.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-7?file=intents.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We are using the &lt;a href="https://octicons.github.com/" rel="noopener noreferrer"&gt;Octicons&lt;/a&gt; icon pack. Now for the rest of the code. Be especially sure to take a look at the Header and the Table files.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-7?file=Header.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;p&gt;Sweet! Now you know how powerful hyperHTML can be. This is pretty much everything there is to learn about the library itself, but we are going to tap into some other utilities provided by &lt;a href="https://medium.com/@WebReflection" rel="noopener noreferrer"&gt;Andrea Giammarchi&lt;/a&gt; to add more tools to our belt. With all these tools combined, we’ll be able to create awesome and high-performing web applications.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>hyperhtml</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Easy apps with hyperHTML — 3, components and state</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Wed, 29 May 2019 14:20:32 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l</guid>
      <description>&lt;h2&gt;
  
  
  Moar about components and simple state management
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://medium.com/easy-apps-with-hyperhtml/aplicaciones-f%C3%A1ciles-con-hyperhtml-3-fc4a0503f498"&gt;Version en español&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part 3 written by &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
  
    .ltag__user__id__60874 .follow-action-button {
      background-color: #353638 !important;
      color: #FFFFFF !important;
      border-color: #353638 !important;
    }
  
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MvWCfXka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--yF4B1j7T--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/60874/62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://twitter.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="twitter logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--oEHrSmvE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-logo.svg"&gt;pinguxx
        &lt;/a&gt;
        &lt;a href="https://github.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;pinguxx
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
  
    .ltag__user__id__171460 .follow-action-button {
      background-color: #093656 !important;
      color: #FFFFFF !important;
      border-color: #093656 !important;
    }
  
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r4dfAuX5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--NSzkAUjv--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/171460/77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://github.com/paritho" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;paritho
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;Introduction, wire/bind&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;Events and components&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Moar about components and simple state management&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;Wire types and custom definitions (intents)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-13hc"&gt;Custom elements with hyper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-1e73"&gt;Customizing my custom elements&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-5b9g"&gt;Testing!&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96"&gt;Async loading, placeholder and a Typeahead with hyper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0"&gt;Handling routes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b"&gt;3rd party libraries&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O0aiCOqG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zibxjb8q14x183bojg6q.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O0aiCOqG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zibxjb8q14x183bojg6q.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;part 2&lt;/a&gt;, we used hyper Components to create a table that can be sorted. Before we add to our table, let’s review the code we previously wrote.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-5?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Table components
&lt;/h3&gt;

&lt;p&gt;Did you notice there are parts of the code we can reuse? If we refactor our code, we can use parts for other tables and it will be easier to maintain those parts instead of updating the entire table for every change. These parts are great candidates for such a refactor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The main table definition&lt;/li&gt;
&lt;li&gt;  The header (row and columns)&lt;/li&gt;
&lt;li&gt;  Body (rows and columns)&lt;/li&gt;
&lt;li&gt;  Footer… well we don’t have a footer yet but we will add one just for fun&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at how we can change these parts to be more maintainable and reusable.&lt;/p&gt;

&lt;h4&gt;
  
  
  Table
&lt;/h4&gt;

&lt;p&gt;First, let’s create a Table.js file and move most of the code there. We won’t need to use bind() in this file, instead we’ll export our Table.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-5-1?embed=1&amp;amp;&amp;amp;file=Table.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Next, let’s update index.js to import our table. This is where we’ll use the bind() function. Recall that bind() works on existing domNodes like document.body. Also note how we’re passing information to the Table: through an object in the constructor.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-5-1?embed=1&amp;amp;&amp;amp;file=index.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h4&gt;
  
  
  Header
&lt;/h4&gt;

&lt;p&gt;Our Header class will extend Component as well.&lt;/p&gt;

&lt;p&gt;Let’s first move the &lt;code&gt;&amp;lt;thead&amp;gt;&lt;/code&gt; element of our table to render(), making it look like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In this template we have onclick listeners attached to our &lt;code&gt;&amp;lt;th&amp;gt;&lt;/code&gt; tags. Since we don’t want to manage the state in this class, we are going to dispatch a custom event called sort. This custom event will have some details about the sorting like the column we are sorting on and if it is ascending or descending.&lt;/p&gt;

&lt;p&gt;We are going to add an update function as well. By using this function, we can be sure we’re always rendering with the current data. If the data changes in the parent, our header will receive the new data. It will look like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Dispatch is a function provided by Component. It will create a custom event with a name based on the first parameter, and the details object based on the second parameter. This is a pretty useful function. Learn more about dispatch() in the &lt;a href="https://viperhtml.js.org/hyperhtml/documentation/#components-3"&gt;documentation&lt;/a&gt;. Our onclick event handler now looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And here’s the complete Header class:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-5-2?embed=1&amp;amp;&amp;amp;file=Header.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now let’s update Table to load the header component. Import again is our friend. Then, in place of the &lt;code&gt;&amp;lt;thead&amp;gt;&lt;/code&gt; mark-up in the render, let’s use the Header class &lt;code&gt;${Header.for(this).update(this.state)}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Component.for its a utility that helps you create components in render(). Instead of creating the component somewhere else, you can create it right there in the function itself. Header.for(object) will then tie the header to the object passed, in this case our current table class, then call update to re-render the header with the state, this will passed on every render. We will use other ways to instantiate the modules later on. Read more in the &lt;a href="https://viperhtml.js.org/hyperhtml/documentation/#components-3"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, we will add an event listener called onsort to the table: &lt;code&gt;onsort="${this}"&lt;/code&gt;. This function will listen to the sorting event we dispatched from the Header. We need to change the &lt;code&gt;onclick&lt;/code&gt; function to &lt;code&gt;onsort&lt;/code&gt;, and we’ll also simplify it a little. The information about the sort is coming in the event detail object. We can then sort the array like before and update the state of the table. Remember, we are passing this state down to the Header class.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let’s take a look at the full code to this point:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-5-2?embed=1&amp;amp;&amp;amp;file=Table.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h4&gt;
  
  
  Body
&lt;/h4&gt;

&lt;p&gt;For our body component, let’s do the same thing — move the &lt;code&gt;tbody&lt;/code&gt; from the render function of the Table to a new component called Body. Body will have its own render function; we’ll put the &lt;code&gt;tbody&lt;/code&gt; code here:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Despite being the component that renders most of our table, this component is actually pretty compact. Let’s see the full file:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-5-3?embed=1&amp;amp;&amp;amp;file=Body.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Notice the line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;this.props = props;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We’ll use this to pass data to the Body component. The information we pass will be the information shown in our Table.&lt;/p&gt;

&lt;p&gt;Now, let’s update Table to load the Body component, using import just like before:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import { Body } from './Body';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this case, let’s mix it up a little bit. Instead of Component.for, let’s create a new Body in the constructor. We don’t need to pass data on instantiation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;this.body = new Body();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With that, we have a table that will work correctly. It will sort, but our data is not really changing (adding or removing). But what if the data does change? We can add the update function inside Body to receive data, just like in Header.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This way we always receive the latest data from the Table. Now, we call the update() function on the Body component directly:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;this.body.update(this.data)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let’s see how it looks.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-5-4?embed=1&amp;amp;&amp;amp;file=Table.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Footer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And as promised… we are going to add a little footer to our table. The footer will show the total number of records. Beside the html for the footer, there is nothing new in this class. Take a look:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-6?embed=1&amp;amp;&amp;amp;file=Footer.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We’ll update the Table component to load the Footer component. Let’s use Component.for and the update function since we always want to receive the latest data. Otherwise, our count of the items in the table will not be accurate.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Footer.for(this).update(this.data)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-6?embed=1&amp;amp;&amp;amp;file=Table.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Aaannddd we are done! We have our simple table with simple state management: we pass data down and events up. We could have used a state management library, Redux or Flux. For our Table, we don’t really need to use anything more complex than what we currently have.&lt;/p&gt;




&lt;p&gt;Before we move on to part 4, let’s explore a small library called &lt;a href="https://proppyjs.com/"&gt;ProppyJS&lt;/a&gt;. ProppyJS isn’t a state management library, but a library that allows us to compose properties. This is useful to compose props from various sources and use them in any component — in essence, we’re allowing ourselves a vast amount of freedom with our apps. With proppy, we could easily attach a redux store if we needed it later, when our component state gets more complex.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-6-p?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We created a prop factory and we use that p everywhere. It condensed our code a lot, and now the header is updating the sort directly. Let us know in the comments if you have questions about implementing ProppyJS.&lt;/p&gt;




&lt;p&gt;We want these tutorials to be as awesome as they can be! If you have feedback, please be sure to leave it in the comments. Thanks for reading, and stay tuned for the next part where we’ll explore a powerful feature called “intents.” Intents will let us expand hyperHTML with custom definitions for our templates.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>hyperhtml</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Easy apps with hyperHTML — 2, Events and components</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Tue, 28 May 2019 14:04:21 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/easy-apps-with-hyperhtml/aplicaciones-f%C3%A1ciles-con-hyperhtml-2-dd264fa495e5"&gt;Version en español&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.lofter.com/lpost/1f16161f_12b7a08fe"&gt;中文版&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part 2 written by &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
  
    .ltag__user__id__60874 .follow-action-button {
      background-color: #353638 !important;
      color: #FFFFFF !important;
      border-color: #353638 !important;
    }
  
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MvWCfXka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--yF4B1j7T--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/60874/62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://twitter.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="twitter logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--oEHrSmvE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-logo.svg"&gt;pinguxx
        &lt;/a&gt;
        &lt;a href="https://github.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;pinguxx
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
  
    .ltag__user__id__171460 .follow-action-button {
      background-color: #093656 !important;
      color: #FFFFFF !important;
      border-color: #093656 !important;
    }
  
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r4dfAuX5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--NSzkAUjv--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/171460/77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://github.com/paritho" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;paritho
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;Introduction, wire/bind&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Events and components&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;Moar about components and simple state management&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;Wire types and custom definitions (intents)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-13hc"&gt;Custom elements with hyper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-1e73"&gt;Customizing my custom elements&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-5b9g"&gt;Testing!&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96"&gt;Async loading, placeholder and a Typeahead with hyper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0"&gt;Handling routes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b"&gt;3rd party libraries&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VXuGYeJS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ttyywhl48ay1jv635ans.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VXuGYeJS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ttyywhl48ay1jv635ans.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you followed along in &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc"&gt;part 1&lt;/a&gt;, you now know the basics to begin working with hyperHTML. We can now dive into more complex topics. Recall the table we made in part 1:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Let’s start by enabling sorting in our column headers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Events
&lt;/h3&gt;

&lt;p&gt;First, we are going to move the render part of our previous example to a function so we can reuse it. We started with this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We’ll change it to this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The next thing we need to do is update our column headers to contain an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tag so the user knows it can be clicked. We’ll also need an event listener to capture the &lt;code&gt;onclick&lt;/code&gt; event. For simplicity, let’s also add a &lt;code&gt;data-target&lt;/code&gt; attribute so we know what attribute the user is trying to sort. With these pieces in place, our &lt;code&gt;&amp;lt;thead&amp;gt;&lt;/code&gt; template will end up like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;What is that &lt;code&gt;onclick&lt;/code&gt;thing? HyperHTML lets us pass a function to the event and it will be called for us. Let’s create a simple sort function to see what we are getting:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The target and ‘this’ are the same in this example. Great! Now we have the anchor tag, which contains the &lt;code&gt;data-target&lt;/code&gt;, that we will use to sort our table. Let’s update our sort function:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;While that is all cool and nice, if the user clicks a second time on the header, it’s not going to reverse the sorting. This is functionality we expect our table to have, so let’s fix that and see how it all works.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-1?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you inspect the table code, you’ll see that only the body rows are being re-painted even tough we are calling display every time. HyperHTML is smart enough to just update the parts that were changed. This illustrates how fast it is, and how cheap its render function is to use.&lt;/p&gt;




&lt;h3&gt;
  
  
  Components
&lt;/h3&gt;

&lt;p&gt;Now that we have our table, it will be easier if we put all of our code related to it in a single place. In addition to cleaning up our code, we’ll be able to re-use this table in other projects. We can accomplish this with a simple object:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-2?embed=1&amp;amp;&amp;amp;file=index.js" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;We have a basic JavaScript object with html as our render variable before, data as our array variable and state. We moved the render() out of the display() function, and notice that we no longer have sort(). Instead, we pass ‘this’ to the onclick event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onclick=${this}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;and handle it with…&lt;/p&gt;
&lt;h4&gt;
  
  
  HandleEvent
&lt;/h4&gt;

&lt;p&gt;This very special function is part of the EcmaScript standard. If an object has it, it will be invoked as &lt;code&gt;obj.handleEvent(e).&lt;/code&gt; This means we can attach an event listener&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;el.addEventListener('click', Table)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;and the click event will be passed to handleEvent function. &lt;code&gt;this&lt;/code&gt; will be the current object (not the element!). This solves a lot of the typical problems we encounter when handling events. For more information you can read all the amazing things handleEvent does here &lt;a href="https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38"&gt;handleEvent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case, we are passing the current object to handleEvent. Now, we just move all the sort functionality inside of this function. Of course we can do more things with this, but this gives us all the functionality we need for sorting the table.&lt;/p&gt;

&lt;p&gt;As an aside, you can also use a function to construct your object, just like you’d expect.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-3?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Pretty much the same as above, the only change is that we added an Id to the table. If you don’t want to use classes, you can go with this approach and hyperHTML wont get in your way.&lt;/p&gt;
&lt;h4&gt;
  
  
  Classes
&lt;/h4&gt;

&lt;p&gt;“That’s all nice and good but what about classes?” you may be thinking. Well, you can use them too.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-4?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And now you have a class, the only thing we changed (besides making it a class) was to call the arguments props, and pass the Id inside an object. Nothing fancy, this just makes it just easier to enhance later on.&lt;/p&gt;

&lt;p&gt;And yes, hyperHTML also has a way to create components in a very easy way. It’s called hyper.Component. This function gives you a few extras I think you’ll find helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  state handling&lt;/li&gt;
&lt;li&gt;  default html attribute binded to itself&lt;/li&gt;
&lt;li&gt;  handleEvent, but even easier!&lt;/li&gt;
&lt;li&gt;  onconnected and ondisconnected functions&lt;/li&gt;
&lt;li&gt;  and more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information about hyper.Component you can read the docs &lt;a href="https://viperhtml.js.org/hyperhtml/documentation/#components-3"&gt;hyper.Component &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enough selling the idea, lets see an actual demo using all the things!!&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table-5?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;First we added Component to our import (hyper.Component that is), then we extend it with the Table. The Component class takes care of “this.html”, so we removed it.&lt;/p&gt;
&lt;h4&gt;
  
  
  Handling events with Component
&lt;/h4&gt;

&lt;p&gt;Where is our handleEvent function?, well component already implements it so we no longer need it either! The way Component defines handleEvent is like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this[‘on’ + event.type](e)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This means if you are listening for a onclick event, handleEvent will receive the event type of “click” and will call &lt;code&gt;this.onclick(e)&lt;/code&gt;, and now we can have our own functions per event type &lt;code&gt;onclick(e) {…}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can even have functions defined to handle custom events! For example, say you are emitting a custom event, “enroll”. You can attach the listener:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onenroll=${this}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;and then handle it inside the component with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onenroll(e){ /* do stuff with the enroll event! */}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Back in our Table, we now have &lt;code&gt;onclick&lt;/code&gt; to handle the click event on the column headers and do the sort.&lt;/p&gt;

&lt;h4&gt;
  
  
  State
&lt;/h4&gt;

&lt;p&gt;Notice we added &lt;code&gt;get defaultState(){...}&lt;/code&gt;. This is a function to return the initial state, so if you haven’t set or updated the state, you’ll get this default object. Read more about it in the &lt;a href="https://viperhtml.js.org/hyperhtml/documentation/#components-3"&gt;documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also added the &lt;code&gt;onclick&lt;/code&gt; (sort function), and a call to the &lt;code&gt;setState&lt;/code&gt; function. SetState will update the state object and will call render for you auto-magically. Other frameworks will update the state asynchronously for “reasons”, but since updates are very fast in hyperHTML setState will fire right away. If you need to update several things, I would recommend constructing an object and then call &lt;code&gt;setState(newobj)&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;We saw a lot of code this time. Hang in there, we are just beginning to scratch the surface of hyperHTML. In the next part, we will see how to use several components in an app, how to do conditional rendering and more details about components.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>hyperhtml</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Easy apps with hyperHTML — 1, wire/bind</title>
      <dc:creator>Ivan</dc:creator>
      <pubDate>Fri, 24 May 2019 20:25:47 +0000</pubDate>
      <link>https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc</link>
      <guid>https://dev.to/pinguxx/easy-apps-with-hyperhtml-1-31cc</guid>
      <description>&lt;h2&gt;
  
  
  hyper what? An introduction to a blazing fast, lightweight JS library.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://medium.com/easy-apps-with-hyperhtml/aplicaciones-f%C3%A1ciles-con-hyperhtml-1-5b887e042c47"&gt;Version en español&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://pinguxx.lofter.com/post/1f16161f_12aa45e3c"&gt;中文版&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Introduction, wire/bind&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-2-hbi"&gt;Events and components&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-3-1m3l"&gt;Moar about components and simple state management&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-4-38k3"&gt;Wire types and custom definitions (intents)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-5-13hc"&gt;Custom elements with hyper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-6-1e73"&gt;Customizing my custom elements&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-7-5b9g"&gt;Testing!&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-8-async-loading-5d96"&gt;Async loading, placeholder and a Typeahead with hyper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-9-routing-59k0"&gt;Handling routes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="https://dev.to/pinguxx/easy-apps-with-hyperhtml-10-3rd-party-libraries-2n7b"&gt;3rd party libraries&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Part 1 written by &lt;/p&gt;
&lt;div class="ltag__user ltag__user__id__60874"&gt;
  
    .ltag__user__id__60874 .follow-action-button {
      background-color: #353638 !important;
      color: #FFFFFF !important;
      border-color: #353638 !important;
    }
  
    &lt;a href="/pinguxx" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MvWCfXka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--yF4B1j7T--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/60874/62ed777d-99a3-400f-8c8c-4e84ddd60519.jpeg" alt="pinguxx image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/pinguxx"&gt;Ivan&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/pinguxx"&gt;standard geek&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://twitter.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="twitter logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--oEHrSmvE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-logo.svg"&gt;pinguxx
        &lt;/a&gt;
        &lt;a href="https://github.com/pinguxx" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;pinguxx
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
 &lt;div class="ltag__user ltag__user__id__171460"&gt;
  
    .ltag__user__id__171460 .follow-action-button {
      background-color: #093656 !important;
      color: #FFFFFF !important;
      border-color: #093656 !important;
    }
  
    &lt;a href="/paritho" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r4dfAuX5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--NSzkAUjv--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/171460/77afa02d-8ec9-403a-8919-6d9e44bdda75.jpg" alt="paritho image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/paritho"&gt;Paul Thompson&lt;/a&gt;
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/paritho"&gt;lover of dogs and javascript.

and coffee.

and writing.&lt;/a&gt;
    &lt;/div&gt;
    &lt;p class="ltag__user__social"&gt;
        &lt;a href="https://github.com/paritho" rel="noopener"&gt;
          &lt;img class="icon-img" alt="github logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C74Jn3f1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo.svg"&gt;paritho
        &lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;While everyone is hyped up about virtual DOM frameworks like React and Vue, I always felt like something was missing. It wasn’t clicking with me that we had to maintain a “copy” of the DOM in memory. I tried a few frameworks, then found Mithril — it has advantages like vanilla JavaScript functions and doesn’t get in the way — but I wasn’t completely satisfied with any of the frameworks.&lt;/p&gt;

&lt;p&gt;Then found the work of &lt;a href="https://medium.com/@WebReflection"&gt;Andrea Giammarchi&lt;/a&gt;. Andrea has worked on tools like vitamer, but then he suddenly published a new, tiny framework called &lt;a href="https://github.com/WebReflection/hyperHTML"&gt;hyperHTML&lt;/a&gt;. After reading his blog post &lt;a href="http://webreflection.blogspot.com/2015/04/the-dom-is-not-slow-your-abstraction-is.html"&gt;The DOM Is NOT Slow, Your Abstraction Is&lt;/a&gt;, I was intrigued. I came to understand how easy was to work with, and loved that everything was just JavaScript functions like Mithril — just 2 functions in the API to learn! Add to that the simplicity of template literals for the templating, and you have a library that is super fast to render your UI changes.&lt;/p&gt;

&lt;p&gt;And no virtual DOM.&lt;/p&gt;

&lt;p&gt;Let’s dive in to some basics about hyperHTML, and then we’ll work on a simple table to apply our knowledge. To get started all you’ll need to know is basic html, and have a good understanding of JavaScript.&lt;/p&gt;

&lt;h4&gt;
  
  
  Basics — template
&lt;/h4&gt;

&lt;p&gt;Templates in hyperHTML are based on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals"&gt;template literals&lt;/a&gt;. They are very easy to use, just a string between backticks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`some string`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But you can also put JavaScript in them and it will be evaluated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`myvar value is ${myvar}`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If myvar = 8; you will get “myvar value is 8”. This is all we need to know to get started with templating in hyperHTML.&lt;/p&gt;

&lt;h4&gt;
  
  
  Basics — Bind
&lt;/h4&gt;

&lt;p&gt;Bind() is one of the 2 functions you have to learn. It renders the template described to the DOM element provided. Bind() differs from wire() (we’ll talk about this in a moment) in that you use bind() to add content to an existing DOM node. Bind returns a function that you can keep reusing to update the contents. For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const render = bind(document.getElementById('app'));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Will bind the element with id “app” to this function so every time we call “render” with a template it will be updated. You can read more about it in &lt;a href="https://viperhtml.js.org/hyperhtml/documentation/#api-0"&gt;the official docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-bind?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;One of the cool features about hyperHTML is that rendering is very fast, and of course it will re-render only the parts that needs to be updated, lets do an example of a simple clock.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-bind-2?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you inspect the element, you will see that only the h2 with the time is updating every second.&lt;/p&gt;

&lt;h4&gt;
  
  
  Basics — wire
&lt;/h4&gt;

&lt;p&gt;The other function that you need to learn is wire(). Wire() returns html from the template provided. You would use wire() where you need to create new DOM nodes. You can generate one element or an array of elements. You can also pass an object (or array), and as a second parameter the type of wire. The default wire method is html, but it can also be svg or just a specific id, so hyperHTML doesn’t re-render it. Read more about it on &lt;a href="https://viperhtml.js.org/hyperhtml/documentation/#api-1"&gt;the official docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this simple example, wire() is returning the h1 for the title:&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/hyperhtml-wire-ex1?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;For this next example, the first array is getting re-rendered every time (check the element inspector), but notice that when we pass an object to wire — wire(obj) — the object is not re-rendered on each tick. This is powerful stuff.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/hyperhtml-wire-ex2?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One small gotcha…&lt;/em&gt; coming from another framework like Vue, you might expect to have partial attributes for your elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="myclass ${classvar}"&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;HyperHTML doesn’t allow this, because in reality it isn’t necessary. However, you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="${`myclass ${classvar}`}"&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Nested backticks solve the problem nicely! For more about why partial attributes are not supported check &lt;a href="https://viperhtml.js.org/hyperhtml/documentation/#essentials-7"&gt;the official docs&lt;/a&gt;.&lt;/p&gt;




&lt;h4&gt;
  
  
  Simple table — 1
&lt;/h4&gt;

&lt;p&gt;Let’s use what we’ve learned so far to write a simple table based on an array. The first step is to create our base html. Then we’ll create our bind function, and finally our template. We are going to use map to iterate over our array to generate rows/columns for the table… and that’s it! Very easy! In Editing Easy Apps with hyperHTML part 2, we are going to add sorting to our table.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/basics-table?embed=1&amp;amp;&amp;amp;" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>hyperhtml</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
