<?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: Samsung Internet</title>
    <description>The latest articles on DEV Community by Samsung Internet (@samsunginternet).</description>
    <link>https://dev.to/samsunginternet</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%2Forganization%2Fprofile_image%2F727%2Fc2cdb110-d195-40f1-9600-abfd5e1e7657.png</url>
      <title>DEV Community: Samsung Internet</title>
      <link>https://dev.to/samsunginternet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/samsunginternet"/>
    <language>en</language>
    <item>
      <title>Immersive Web, Docker and problem with symbolic links for SSL certificates.</title>
      <dc:creator>Sylwester Mielniczuk</dc:creator>
      <pubDate>Fri, 10 Jun 2022 09:53:19 +0000</pubDate>
      <link>https://dev.to/samsunginternet/immersive-web-docker-and-problem-with-symbolic-links-for-ssl-certificates-45o0</link>
      <guid>https://dev.to/samsunginternet/immersive-web-docker-and-problem-with-symbolic-links-for-ssl-certificates-45o0</guid>
      <description>&lt;h2&gt;
  
  
  Interactive Wall at GAM in Turin
&lt;/h2&gt;

&lt;p&gt;As an &lt;strong&gt;Immersive Web Developer&lt;/strong&gt; from time to time, there is a need to play the role of &lt;strong&gt;DevOps engineer&lt;/strong&gt;. Mostly because the prototype of my research project needed to be deployed to production cloud infrastructure &lt;strong&gt;(&lt;a href="https://www.5g-eve.eu/"&gt;5G EVE&lt;/a&gt;)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Despite the complexity of the overall 5G research, my web application is relatively weak, called &lt;strong&gt;"Interactive Wall"&lt;/strong&gt; is designed for a multi-device experience with blazing fast animation purposes WebGL canvas (&lt;a href="https://pixijs.io/"&gt;PixiJS&lt;/a&gt;). Depending on the provided parameters there are two types of UIs: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For students (kids or other pupils) - (multiplayer)&lt;/li&gt;
&lt;li&gt;The teacher(s) (or other guardians) - (single user)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first one is displayed on the wall via projector, the second can be opened via QR code on the mobile device, wearable or any other desktop running Chromium-based browsers. Realtime communication between both interfaces is established via &lt;a href="https://github.com/websockets/ws"&gt;WebSocket&lt;/a&gt; server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lsI75HAi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/soend0j23ozzh82p6wvv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lsI75HAi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/soend0j23ozzh82p6wvv.gif" alt="Immersive Web" width="640" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The GIF above showcases a WebSocket connection between 2 tabs of the browser, mobile and wearable device. The latency between them is about and above 30ms but depends on the hardware and network characteristics. We were aiming to measure all the advantages of having 20 times faster connections than 4G.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to uncommon HID devices.
&lt;/h2&gt;

&lt;p&gt;Paired and connected via Bluetooth thanks to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebHID_API"&gt;WebHID API&lt;/a&gt; - old good and forgotten almighty Nintendo Wiimote. Its camera for direction reports is calibrated by IR Bar, and all the motion, acceleration and input data from 11 buttons are sent via Bluetooth to the browser. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is actually WebHID?&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;sup&gt;"HID consists of two fundamental concepts: reports and report descriptors. Reports are the data that is exchanged between a device and a software client. The report descriptor describes the format and meaning of data that the device supports.&lt;br&gt;
An HID (Human Interface Device) is a type of device that takes input from or provides output to humans. It also refers to the HID protocol, a standard for bi-directional communication between a host and a device that is designed to simplify the installation procedure. The HID protocol was originally developed for USB devices, but has since been implemented over many other protocols, including Bluetooth." - &lt;a href="https://web.dev/hid/"&gt;https://web.dev/hid/&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was able to use simultaneously more than 4 controllers. Originally developed for one Wiimote by a former colleague at Samsung &lt;a href="https://picchikevin.github.io/wiimote-webhid/"&gt;Kevin Picchi&lt;/a&gt;. I have developed a multiuser version for &lt;a href="http://5gtours.eu/"&gt;5G Tours consortium&lt;/a&gt;. It's a really long story. &lt;/p&gt;

&lt;h2&gt;
  
  
  Portable Deployment
&lt;/h2&gt;

&lt;p&gt;In general, the browser UI can be statically provided separately from the WebSocket server but for the sake of portability, decided to pack everything all together as &lt;a href="https://nodejs.org/"&gt;Node.JS&lt;/a&gt; project, perfect for scalable web applications. Portable deployment should be easy with &lt;a href="https://www.docker.com/resources/what-container/"&gt;Docker&lt;/a&gt;. There is super simple &lt;a href="https://nodejs.org/en/docs/guides/nodejs-docker-webapp/"&gt;tutorial how to do bake nodejs-docker-webapp&lt;/a&gt;. Basic use of Docker is free and you can install it on Mac, Windows and Linux. You need to write a relatively simple Dockerfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# The name of the image for your container
FROM node:16

# Create app directory, copy configuration assets
WORKDIR /usr/src/app
COPY package*.json ./

# Install npm
RUN npm install

# Bundle app source
COPY . .

# Optional exposed app ports
EXPOSE 8080

# Available commands from CLI
CMD [ "node", "index-wall.js" ]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To build the image run this command from the folder where your Dockerfile and assets are located. &lt;br&gt;
&lt;code&gt;$ docker build . -t flaboy/node-wall&lt;/code&gt;&lt;br&gt;
flaboy/node-wall is the given name of image, when it's created you can push and pull this like git repo to the docker.io repository.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker push flaboy/node-wall&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you need to share image file this is the way you can export tarball:&lt;br&gt;
&lt;code&gt;$ docker save flaboy/node-wall &amp;gt; node-vr.tar&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Later someone can load the archived image as follows:&lt;br&gt;
&lt;code&gt;$ docker load &amp;lt; node-vr.tar&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Deploying such an image seems to be super simple. On the server with a fully qualified domain and web server and reverse proxy &lt;a href="https://nginx.org/"&gt;Nginx&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The only little problem is those files required by server web application via HTTPS, ie SSL certificates. Where they are located? It depends on how you managed such certificates. I use &lt;a href="https://letsencrypt.org/"&gt;letsEncrypt&lt;/a&gt; Certbot. &lt;/p&gt;

&lt;p&gt;Your browser lock at the location bar says:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SwsdiLoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w82kljpi0a0537o4jsmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SwsdiLoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w82kljpi0a0537o4jsmt.png" alt="This is what you see" width="777" height="659"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These chains of trust hierarchy technically have this structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hGrJ6VGC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40mikmhsum3c7lqtjetv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hGrJ6VGC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40mikmhsum3c7lqtjetv.png" alt="Chain of Trust" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Let's Encrypt Certbot hints
&lt;/h1&gt;

&lt;p&gt;Installation:&lt;br&gt;
&lt;code&gt;$ sudo apt install certbot python3-certbot-nginx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Get your domain SSL certificates:&lt;br&gt;
&lt;code&gt;$ sudo certbot --nginx -d your.domain.name&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The architecture is organized by certbot in this folder: &lt;code&gt;/etc/letsencrypt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YRvUjI5j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64w5o61mtw93o3yvla8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YRvUjI5j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64w5o61mtw93o3yvla8q.png" alt="/etc/letsencrypt/" width="816" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the domain name specific files are saved to &lt;code&gt;/etc/letsencrypt/archive/your.domain.name&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So these files are archived under the following numbers (because certbot already renewed cert files so far several times). The latest ones are exposed to the &lt;code&gt;/etc/letsencrypt/live/&lt;/code&gt; folder. as symbolic links (&lt;a href="https://man7.org/linux/man-pages/man2/symlink.2.html"&gt;symlinks&lt;/a&gt;) without numbers in their names.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;sup&gt;- Symbolic links are interpreted at run time as if the contents of the link had been substituted into the path being followed to find a file or directory. - Symbolic links may contain ..  path components, which (if used at the start of the link) refer to the parent directories of that in which the link resides. - A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent one; the latter case is known as a dangling link..&lt;/sup&gt;&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root [letsencrypt] $ more /etc/letsencrypt/live/your.domain.name/README 
This directory contains your keys and certificates.

`privkey.pem`  : the private key for your certificate.
`fullchain.pem`: the certificate file used in most server software.
`chain.pem`    : used for OCSP stapling in Nginx &amp;gt;=1.3.7.
`cert.pem`     : will break many server configurations, and should not be used
                 without reading further documentation (see link below).

WARNING: DO NOT MOVE OR RENAME THESE FILES!
         Certbot expects these files to remain in this location in order
         to function properly!

We recommend not moving these files. For more information, see the Certbot
User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Coming back to the Docker. We have pulled the image and we would love to run the web app. The problem is that the container needs to read SSL certificates (exposed as symbolic links) from the outside of the Docker virtual container. They are required to run the web app securely via HTTPS. The paths to the key and certificate are provided in the main Node.js app file: &lt;code&gt;index-wall.js&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;const server = https.createServer({
    key: fs.readFileSync('/ssl/privkey.pem'),
    cert: fs.readFileSync('/ssl/fullchain.pem')
}, app);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is how it can not be run with mounted volumes -v ( --volume). &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker run -v /etc/letsencrypt/live/your.domain.name:/ssl -d -p 4444:8080 flaboy/node-wall node index-wall.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Docker unfortunately is not able to read symlinks from provided volumes (-v). You can check the error logs this way:&lt;br&gt;
&lt;code&gt;$ docker logs containerid&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;root [letsencrypt] $ docker logs 8d2b81a25359
node:internal/fs/utils:345
    throw err;
    ^

Error: ENOENT: no such file or directory, open '/ssl/privkey.pem'
    at Object.openSync (node:fs:585:3)
    at Object.readFileSync (node:fs:453:35)
    at Object.&amp;lt;anonymous&amp;gt; (/usr/src/app/index-wall.js:18:13)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47 {
  errno: -2,
  syscall: 'open',
  code: 'ENOENT',
  path: '/ssl/privkey.pem'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  You need to use bind mounts
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;What are bind mounts?&lt;/strong&gt;&lt;/em&gt; As per &lt;a href="https://docs.docker.com/storage/bind-mounts/"&gt;Docker documentation&lt;/a&gt;, we can read that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[...] Bind mounts have limited functionality compared to volumes. When you use a bind mount, a file or directory on the host machine is mounted into a container. The file or directory is referenced by its absolute path on the host machine. By contrast, when you use a volume, a new directory is created within Docker’s storage directory on the host machine, and Docker manages that directory’s contents.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Detailed instruction on the bind mounts syntax:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;--mount&lt;/strong&gt;: Consists of multiple key-value pairs, separated by commas and each consisting of a &lt;code&gt;&amp;lt;key&amp;gt;=&amp;lt;value&amp;gt;&lt;/code&gt; tuple. - The --mount syntax is more verbose than &lt;code&gt;-v&lt;/code&gt; or &lt;code&gt;--volume&lt;/code&gt;, but the order of the keys is not significant, and the value of the flag is easier to understand.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The type of the mount, which can be bind, volume, or tmpfs. [...] The type is always bind.&lt;/li&gt;
&lt;li&gt;The source of the mount. For bind mounts, this is the path to the file or directory on the Docker daemon host. May be specified as source or src.&lt;/li&gt;
&lt;li&gt;The destination takes as its value the path where the file or directory is mounted in the container. May be specified as destination, dst, or target.&lt;/li&gt;
&lt;li&gt;The readonly option, if present, causes the bind mount to be mounted into the container as read-only.&lt;/li&gt;
&lt;li&gt;The bind-propagation option, if present, changes the bind propagation. May be one of rprivate, private, rshared, shared, rslave, slave.&lt;/li&gt;
&lt;li&gt;The --mount flag does not support z or Z options for modifying selinux labels.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;So let's try to mount 2 cert files (&lt;strong&gt;sources&lt;/strong&gt;):&lt;br&gt;
&lt;code&gt;/etc/letsencrypt/live/your.domain.name/privkey.pem&lt;/code&gt;&lt;br&gt;
and &lt;code&gt;/etc/letsencrypt/live/your.domain.name/fullchain.pem&lt;/code&gt; as they would exist inside docker container inside &lt;code&gt;/ssl/&lt;/code&gt; folder (&lt;strong&gt;target&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker run --mount type=bind,source=/etc/letsencrypt/live/your.domain.name/privkey.pem,target=/ssl/privkey.pem --mount type=bind,source=/etc/letsencrypt/live/your.domain.name/fullchain.pem,target=/ssl/fullchain.pem -d -p 4444:8080 flaboy/node-wall node index-wall.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Is the app running?&lt;br&gt;
&lt;code&gt;$ docker ps -a&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;9990433c624d   flaboy/node-wall   "docker-entrypoint.s…"   4 minutes ago   Up 4 minutes                 0.0.0.0:4444-&amp;gt;8080/tcp, :::4444-&amp;gt;8080/tcp   hardcore_nash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Yes! That's all people!
&lt;/h2&gt;

&lt;p&gt;Here is my video on how it did not work properly with -v&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=doS0L6nBeKg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ohz0F_34--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.youtube.com/vi/doS0L6nBeKg/0.jpg" alt="Here is how it did not work with -v" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is working properly with the latest SSL&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=1rRZRmLt7s4"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dcSi2AMW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.youtube.com/vi/1rRZRmLt7s4/0.jpg" alt="And here is working properly SSL" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you would love to play with &lt;a href="https://xr.workwork.fun:4444"&gt;Interactive Wall&lt;/a&gt;, it's deployed to: &lt;a href="https://xr.workwork.fun:4444"&gt;https://xr.workwork.fun:4444&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app works on Mac, and Windows (you might need also Nintendo &lt;br&gt;
 emulator &lt;strong&gt;&lt;a href="https://dolphin-emu.org/"&gt;Dolphin&lt;/a&gt;)&lt;/strong&gt;. You just need a Chromium-based browser (Edge, Brave, Chrome), also get your &lt;strong&gt;original Wiimote(s) Plus&lt;/strong&gt; (cheap, the third party rather does not work). Do not forget to charge your batteries. Infrared direction calibrator &lt;strong&gt;Mayflash W010 Dolphin Bar&lt;/strong&gt; is necessary, get it from the &lt;a href="https://www.amazon.co.uk/Mayflash-W010-Dolphin-Bar-Wireless/dp/B00HZWEB74"&gt;Amazon&lt;/a&gt;. The WebHID API and amount of Bluetooth devices might be limited on Windows but Bluetooth standard might allow connecting lots of devices so having multiple input devices connected to the web browser interface at the same time is an amazing opportunity for multiplayer experiences without any game-server involved. &lt;em&gt;Just think about this a little bit!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Students UI&lt;br&gt;
&lt;a href="https://xr.workwork.fun:4444"&gt;https://xr.workwork.fun:4444&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Teachers UI (open from provided QR code)&lt;br&gt;
&lt;a href="https://xr.workwork.fun:4444/?u=teacher&amp;amp;p=pass1"&gt;https://xr.workwork.fun:4444/?u=teacher&amp;amp;p=pass1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OdjgTlLv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/teopgxe6dta37kbkx5op.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OdjgTlLv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/teopgxe6dta37kbkx5op.png" alt="Image description" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More about &lt;strong&gt;5GTours&lt;/strong&gt; project you can find in D4.4 public document on &lt;a href="http://5gtours.eu/deliverables/"&gt;http://5gtours.eu/deliverables/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webhidapi</category>
      <category>immersiveweb</category>
      <category>smartcity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>From Bootstrap to Grid</title>
      <dc:creator>Lola</dc:creator>
      <pubDate>Thu, 21 Apr 2022 16:43:13 +0000</pubDate>
      <link>https://dev.to/samsunginternet/from-bootstrap-to-grid-1c31</link>
      <guid>https://dev.to/samsunginternet/from-bootstrap-to-grid-1c31</guid>
      <description>&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Bootstrap Way&lt;/li&gt;
&lt;li&gt;The Problem&lt;/li&gt;
&lt;li&gt;CSS-Grid&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display: flex&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Combining CSS-Grid with Flexbox&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;Further Watching&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This post isn't going to be a CSS-grid tutorial, there are loads out there, &lt;a href="https://medium.com/samsung-internet-dev/common-responsive-layouts-with-css-grid-and-some-without-245a862f48df" rel="noopener noreferrer"&gt;Jo even wrote one&lt;/a&gt; and since, CSS Grid has emerged as vita tool to enable responsive design. This is a post about how to understand the difference between traditional CSS layout frameworks (Bootstrap, Tailwind, Foundation, etc) &amp;amp; CSS-grid.&lt;/p&gt;

&lt;p&gt;I’ve been building things on the web for almost 8yrs &amp;amp; in that time, Bootstrap has been my layout framework of choice. When I began developing on the web, creating responsive layouts in vanilla CSS was intimidating, especially as a Ruby, predominately back-end, engineer but thankfully, CSS has continued to evolve in that time and now we have CSS-grid. Despite this though, many developers still opt to use frameworks which impact the load of their websites and web apps when they don’t need to. I know for me, CSS-grid was still intimidating, I didn’t understand when to use that vs when to use flexbox or if I could use them together. In this post I’m going to try to explain how CSS-grid (&amp;amp; flexbox) work if you’re coming from a framework such as Bootstrap.&lt;/p&gt;

&lt;p&gt;To learn and understand CSS-grid I decided to create a grid for my website since the layout is fairly simple and there are few elements on the screen. I marked up the grid and any sub-grids I used to get a clear understanding of where the elements are positioned. The red dashed lines are are the main grid while the yellow marks the sub-grid.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyudn3n0xtht7vxsq1fd2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyudn3n0xtht7vxsq1fd2.png" alt="the lolaodelola.dev site with red markings to show the current main grid and yellow markings to show the sub-grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without the use of any layout framework, the elements use the original HTML flow&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26ajj9170b2pvbtl34kb.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26ajj9170b2pvbtl34kb.png" alt="the lolaodelola.dev site without any layout frameworks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was able to recreate the layout, with only two changes (the positioning of the header) and make it fully responsive to width without any media queries.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdahe3i618t5pvq2okpme.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdahe3i618t5pvq2okpme.gif" alt="a gif of the responsiveness of lolaodelola.dev using css-grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bootstrap Way
&lt;/h2&gt;

&lt;p&gt;Bootstrap typically work by defining a fixed, 12 column grid, while this number and the fixed width has historical context it’s mostly arbitrary, especially now considering the diversity in viewport dimensions. With this fixed width column system, you define how many columns your elements should take up at various viewport widths within a container e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-3-lg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example defines a container then says the child element should take up 3 columns on a large screen, which in Bootstrap is a screen width of ≥992px. Other frameworks approach this in a different way, for example Tailwind actually uses CSS-grid under the hood. Bootstrap is also mobile-first and in the most recent version, if you have child elements that should take up an equal amount of space, regardless of device width, you don’t have to specify a unit e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the past Boostrap used CSS floats under the hood, however the current version, Bootstrap 5.1 uses flexbox (which I’ll go into more detail later).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Bootstrap is a good way to quickly create a layout, especially if that layout is one of the few basic layouts that are used on the web. It has an extensive list of class definitions for developers to choose from, the documentation is robust and it’s free to use, there’s a place for Bootstrap. But choosing to use it should be intentional and not because you’re intimidated by CSS-grid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inflexiblity
&lt;/h3&gt;

&lt;p&gt;In Ruby on Rails development, the methodology is “convention over configuration” which is to say it’s easier (read: better) to do things as they’re defined than it is to try and customise the framework to meet your needs. I think most frameworks, regardless of language, work in this way. While Bootstrap is robust, it isn’t flexible. The minute you want to create layouts that don’t follow the rules of a 12 column grid, or have elements doing interesting things like overlapping, or even decide to adjust the layout dependent on height instead of width, things begin to get complicated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Obscures the CSS
&lt;/h3&gt;

&lt;p&gt;The job of a framework is to create a sort of instruction manual of using a language in a certain way to build certain things. So, yes, frameworks will naturally obstruct the vanilla language being used to construct them however, Bootstrap goes an extra mile to redefine things that can be easily defined in one rule, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.d-flex&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a rule that can easily be defined within the custom CSS, without the &lt;code&gt;!important&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;On the topic of &lt;code&gt;!important&lt;/code&gt; this is another place where CSS is obscured, the keyword is litered all through the framework and should you be using Bootstrap in conjuction with another stylesheet, especially on big projects, you will have to be careful and aware of the order of how your stylesheets are being loaded and where styles may be overwritten.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overbloat
&lt;/h3&gt;

&lt;p&gt;Because Bootstrap tries to cover many basis, there are inevitably rules and styles you won’t end up using but these styles will still be loaded into the site. Bootstrap also comes with a visual identity, there are styles for all kinds of elements, buttons, navs, leads, etc but even if you elect to just include the grid in your project, you won’t be using all aspects of the grid. In fact, it’s possible you may just use 3 or 4 grid properties but will still be loading a 53KB file (if only using &lt;code&gt;bootstrap-grid.min.css&lt;/code&gt; ), my custom grid.css file for this project ended up being only 881bytes without being minified and is only 62 lines long.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS-Grid
&lt;/h2&gt;

&lt;p&gt;Learning CSS-grid requires unlearning Bootstrap (or which framework you’re using if it’s not using grid under the hood). Before I get into the minutiae, it’s important to note that CSS-grid encourages you to have multiple grids on a page where as Bootstrap assumes you have one main grid which you nest elements within. CSS-Grid says apply the grid where you need it, which really encourages you to think about the default display of elements (which elements are block, which are inline and do you need to flex anything?).&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Column, What is a Row, What is a Cell?
&lt;/h3&gt;

&lt;p&gt;Any grid framework or understanding works on a x-axis and a y-axis, it’s 2-dimensional in that way, this  may seem like an obvious fact but is important to remember. Within Bootstrap, columns and rows work in the traditional way. A row is horizontal space while a column is a vertical space. In the image below the green dotted line around the perimeter of the elements indicates the row while the dotted line down the middle separates the columns. So there is one row and two columns. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4tzqmcgmlqmwd42tryq.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4tzqmcgmlqmwd42tryq.png" alt="the lolaodelola.dev site with the dev tools layout grid showing the columns in a green dashed line"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This would be defined in the HTML as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is to say both the row and the column refer to the space between the lines of the grid, rather than the lines themselves. In other words, we define the row and column on the page and fill both with content.&lt;/p&gt;

&lt;p&gt;CSS-grid also uses rows and columns but not in the same way. In grid, the columns and rows refer to the lines rather than the space between the lines.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpiduzhrkgnej0r0mwhqe.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpiduzhrkgnej0r0mwhqe.png" alt="the dev tools layout shows where the column and row lines are when the page has multiple columns"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although difficult to see, each line is numbered. The numbers in this image refer to the rows and columns, so the first vertical line is column 1, the second is column 2, and the first horizontal line is row 1 and the second is row 2. The space in between these lines, the cell, contains the image. Similarly, the block of text starts at horizontal line 2 i.e. column 2 and ends at horizontal line 3 i.e. column 3 and also starts at vertical line 1 i.e. row 1 and ends at vertical line 2, i.e. row 2.&lt;/p&gt;

&lt;p&gt;And when the page collapses into a single column the image is still starts at column 1 and ends at column 2 and starts at row 1 and ends at row 2 but the block of text now also starts tarts at column 1 and ends at column 2 but sits between row 2 &amp;amp; 3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The space between the rows and columns is called a cell&lt;/strong&gt;. So the image sits in a cell that between two columns and two rows.&lt;/p&gt;

&lt;p&gt;The CSS and HTML for this aren’t complex&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!--Grid cell 1 --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Grid cell 2 --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"about"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto-fit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="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%2Farticles%2Fbouj3u7xejyghgq153al.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbouj3u7xejyghgq153al.png" alt="the dev tools layout shows where the column and row lines are when the page is in single column"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will go into detail about &lt;code&gt;grid-template-columns&lt;/code&gt; a little later but the important thing here is that I’m defining a grid on the parent element (similarly to how you might define a container in bootstrap) and then telling the CSS how I want the grid to look i.e. how I want elements to occupy the available space.&lt;/p&gt;

&lt;p&gt;If I want the elements to span multiple columns or rows, I can define that in the CSS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;
&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will cause the image to start at column 1/row1 and end at column 3/row3, which will occupy 2 cells. If I wanted to have an element occupy 2 cells with Bootstrap, I’d give the element a &lt;code&gt;.col-2&lt;/code&gt; however, remember that Bootstrap works on a fixed-width grid and CSS-grid doesn’t. Play with this on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column" rel="noopener noreferrer"&gt;MDN to really get to grips with it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/grid-area#examples" rel="noopener noreferrer"&gt;You can also define a &lt;code&gt;grid-area&lt;/code&gt;&lt;/a&gt; which is a combination of the rows and columns. &lt;/p&gt;

&lt;h3&gt;
  
  
  Fractions (aka FR)
&lt;/h3&gt;

&lt;p&gt;With CSS-grid comes a new unit to define how much space elements should take up. While it’s entirely fine to use &lt;code&gt;px&lt;/code&gt;, &lt;code&gt;ch&lt;/code&gt;, &lt;code&gt;em&lt;/code&gt;, &lt;code&gt;rem&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt;, etc &lt;code&gt;fr&lt;/code&gt; (fraction) is a little more flexible in the context of grid.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned earlier, the &lt;code&gt;grid-template-columns&lt;/code&gt; defines the vertical space the elements in my grid should occupy. I can define the same for rows with &lt;code&gt;grid-template-rows&lt;/code&gt; but for now let’s focus on columns. In the CSS above, I’ve said that each column should take one fraction of the available grid space. Regardless of the viewport width, the grid cells will only take up 1 fraction of space in the grid.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31k3tbqjf9kyson224zj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31k3tbqjf9kyson224zj.png" alt="When the screen width is too small, the text becomes very cramped and the image very small side by side"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So even on smaller devices the elements will still try to take up 1 fraction of the available grid. Of course, you can use any fraction here, &lt;code&gt;2fr&lt;/code&gt;, &lt;code&gt;7fr&lt;/code&gt;, etc and mix and match. You can also tailor to consider how many cells will be in the grid and define those too, so if my grid had 4 cells I could say &lt;code&gt;grid-template-columns: 1fr 1fr 1fr 1fr&lt;/code&gt; to say I want 4 cells and each should take up 1 fraction of the available grid space. You can also mix and match different units to get your ideal layout, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns" rel="noopener noreferrer"&gt;have a go on MDN&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gaps aka Gutters
&lt;/h3&gt;

&lt;p&gt;The grid gutter in Bootstrap is the space between columns and rows, in the image below each column has a box around the perimeter and a space in the middle which is the gutter.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flszavydehvybqmpjfetm.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flszavydehvybqmpjfetm.png" alt="the two columns have boxes around them with a gap between them"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While the gutters in Bootstrap can be redefined, most users use the default gutters and don’t have to consider them. With grid, gutters are called gaps and you also may not have to define gaps on grid dependent on the units you choose to define the columns but implementing gaps is straight-forward. You have the option of defining the &lt;code&gt;column-gap&lt;/code&gt;, &lt;code&gt;row-gap&lt;/code&gt; or for if you want both the vertical and horizontal gaps to be the same then &lt;code&gt;gap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Gaps can also be used to define the space within flex elements, so if you plan to nest grids within flex elements, and are defining gaps on both the grid and flex element, you may find your gaps are slightly wider than you anticipate. The solution is to adjust them as you see fit. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/gap" rel="noopener noreferrer"&gt;You can play with gaps on MDN.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Get Responsive without Media Queries
&lt;/h3&gt;

&lt;p&gt;As I mentioned earlier, I was able to recreate the responsiveness of my original site without using media queries. This requires a combination of rules to create the fluidity of a responsive web page.&lt;/p&gt;

&lt;p&gt;First up, &lt;code&gt;repeat&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This says create 2 columns each taking up 1 fraction of space in the grid, the issue here is that on smaller viewports, there will be 2 squished cells which isn’t want we want.&lt;/p&gt;

&lt;p&gt;To overcome this hurdle, we can define the minimum width for the columns using &lt;code&gt;minmax&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we’re saying we want &lt;code&gt;2&lt;/code&gt; columns, with a minimum of &lt;code&gt;50ch&lt;/code&gt; width, taking up &lt;code&gt;1fr&lt;/code&gt; of the available space.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foky3fnwoiial99btcck4.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foky3fnwoiial99btcck4.png" alt="when the screen width is too small, the column to the right overflows"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This presents a new problem, when we’re on devices with a viewport width that’s smaller than the available row space, the content will overflow. This is also unideal, so there’s one more part to enable the cells collapsing like we expect.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;auto-fit&lt;/code&gt;/ &lt;code&gt;auto-fill&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto-fit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’ve decided to use &lt;code&gt;auto-fit&lt;/code&gt; here which collapses the columns into rows as we expect. &lt;code&gt;auto-fit&lt;/code&gt; and &lt;code&gt;auto-fill&lt;/code&gt; have similar functions in that they both look at the available space in a row and assign column space to the available cells. Sara Soueidan explains the difference as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;code&gt;auto-fill&lt;/code&gt; FILLS the row with as many columns as it can fit. So it creates implicit columns whenever a new column can fit, because it’s trying to FILL the row with as many columns as it can. The newly added columns can and may be empty, but they will still occupy a designated space in the row. &lt;br&gt;
&lt;code&gt;auto-fit&lt;/code&gt; FITS the CURRENTLY AVAILABLE columns into the space by expanding them so that they take up any available space. The browser does that after FILLING that extra space with extra columns (as with &lt;code&gt;auto-fill&lt;/code&gt; ) and then collapsing the empty ones.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I recommend reading the &lt;a href="https://css-tricks.com/auto-sizing-columns-css-grid-auto-fill-vs-auto-fit/#aa-fill-or-fit-whats-the-difference" rel="noopener noreferrer"&gt;full explainer&lt;/a&gt; to really get your head around the difference.&lt;/p&gt;

&lt;p&gt;The combination of &lt;code&gt;repeat&lt;/code&gt;, &lt;code&gt;minmax&lt;/code&gt; and &lt;code&gt;auto-fit&lt;/code&gt;/ &lt;code&gt;auto-fill&lt;/code&gt; creates a layout that’s responsive to width without media queries and in one line.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;display: flex&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Flexbox deserves its own post so I won’t go into too much detail here but it’s important to know how it fits in with grid. Many people aren’t only intimidated by CSS-grid, but also by Flexbox and the difference is between the two. Coming from Bootstrap, it’s tricky to know when to use either. The good news is you can use both but they do serve different purposes.&lt;/p&gt;

&lt;p&gt;As I mentioned before CSS-grid works along the X-axis and Y-axis, it’s 2-dimensional. Flexbox only works along the X-axis, which is the horizontal axis and so it’s 1-dimensional. Adding elements to a flex element will cause the elements to flow horizontally.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgjzqbc7zs6ojd0q3h2a.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgjzqbc7zs6ojd0q3h2a.png" alt="The flex container for the nav. Each item is in its own box with the surrounding space shaded in."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the example above, I have a &lt;code&gt;ul&lt;/code&gt; element which usually stacks its list items vertically, however, since I’ve given the element a &lt;code&gt;display: flex&lt;/code&gt; the elements are lined up horizontally. It’s possible to allow flex elements to stack vertically to avoid overflow with &lt;code&gt;flex-wrap: wrap&lt;/code&gt; as I’ve done for the list of buttons here:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdi5skmq253h17bnuj1e.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdi5skmq253h17bnuj1e.gif" alt="A gif of the responsive buttons created using flex"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The CSS for this is two lines&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Justify &amp;amp; Align Content
&lt;/h3&gt;

&lt;p&gt;The super power of Flexbox is being able to justify and align content the way we want. Aligning content positions the element along its own y-axis, while justify position an element along its own x-axis. &lt;/p&gt;

&lt;h2&gt;
  
  
  Combining CSS-Grid with Flexbox
&lt;/h2&gt;

&lt;p&gt;Okay, so we can kinda grasp CSS-Grid and Flexbox how and why would we put them together? Let’s revisit my very first image with the Bootstrap grid outlines:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1yohgpwwft6rf7kocyq.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1yohgpwwft6rf7kocyq.png" alt="the lolaodelola.dev site with red markings to show the current main grid and yellow markings to show the sub-grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To recap, the red dashed lines are the main grid and the yellow lines are the subgrid. Breaking this down I can see that I think I want 2 columns and 3 rows for the main grid, however CSS-Grid forces us to only use the grid where necessary. This is where personal preference comes into play, there aren’t any concrete rules here, it’s entirely up to me and how I want to lay this out. Bootstrap’s approach to this would be to make all the columns flex elements and wrap them as necessary and not use the grid at all.&lt;/p&gt;

&lt;p&gt;The method I ended up going with was a combination of CSS-Grid and Flexbox.&lt;/p&gt;

&lt;p&gt;I changed my mind about the layout to be a little more accesible. The previous layout would have screenreaders reading the image before the title which isn’t ideal. I’ve moved the title into a header with the nav, and since neither the header or the footer needs to work on a 2-dimensional level (or can just without changing the native display properties of the elements), I’ve decided to only apply the grid to the main content. The red dashed line shows 3 columns, 2 rows which create space for 2 cells.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2vcw9vyo3a6xl7iis4e.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2vcw9vyo3a6xl7iis4e.png" alt="the new lolaodelola.dev layout with red dashed lines outlining the grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve moved the title into a header with the nav, and since neither the header or the footer needs to work on a 2-dimensional level (or can just without changing the native display properties of the elements), I’ve decided to only apply the grid to the main content. The red dashed line shows 3 columns, 2 rows which create space for 2 cells.&lt;/p&gt;

&lt;p&gt;I’ve decided to use flex for elements which normally have a &lt;code&gt;display: block&lt;/code&gt; so that they can flow horizontally, wrap if necessary and are justified and aligned as expected on all screen sizes.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffx3v997ycj8h83b251e2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffx3v997ycj8h83b251e2.png" alt="the new lolaodelola.dev layout with yellow dashed lines outlining the the flex elements, some of which are a sub-grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;CSS-Grid is very robust and there are definitions that I didn’t cover here, such as &lt;code&gt;grid-template-areas&lt;/code&gt; which allows you to define sections of a page with different grids to create a layout, it also allows for empty cells (without defining empty HTML elements). Or grid ordering which lets you define the order of cells within a grid in the CSS.&lt;/p&gt;

&lt;p&gt;One of the qualities of Bootstrap is that there’s the option to create sub-grids fairly easily and while it’s possible to nest grids with CSS-grid, there is a dedicated sub-grid &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Subgrid" rel="noopener noreferrer"&gt;ruleset on its way&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Further Watching
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=AMPKmh98XLY&amp;amp;t=225s" rel="noopener noreferrer"&gt;“Designing Intrinsic Layouts” by Jen Simmons—An Event Apart video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=dQHtT47eH0M&amp;amp;t=56s" rel="noopener noreferrer"&gt;Using Flexbox + CSS Grid Together: Easy Gallery Layout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=mVQiNpqXov8" rel="noopener noreferrer"&gt;MinMax in CSS Grid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>grid</category>
      <category>frameworks</category>
    </item>
    <item>
      <title>The Trouble with `has_one`</title>
      <dc:creator>Lola</dc:creator>
      <pubDate>Tue, 10 Aug 2021 13:19:27 +0000</pubDate>
      <link>https://dev.to/samsunginternet/the-trouble-with-hasone-261m</link>
      <guid>https://dev.to/samsunginternet/the-trouble-with-hasone-261m</guid>
      <description>&lt;p&gt;Recently I was working on my dissertation and came across an interesting problem with using the has_one association in Rails. But before we get into that, let’s take a step back to understand a little about how associations work in Rails.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/l0HlI6NdcrtkV5C7e/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/l0HlI6NdcrtkV5C7e/giphy.gif" alt="A woman on big brother looking confused"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rails Associations
&lt;/h2&gt;

&lt;p&gt;I’m not going to assume everyone reading this knows or understands in depth about databases and object relational mappers so I’ll try to keep this brief and simple. If you want a more in depth understanding, the &lt;a href="https://guides.rubyonrails.org/association_basics.html"&gt;Rails docs&lt;/a&gt; are a good starting point to understanding this in that specific context.&lt;/p&gt;

&lt;p&gt;Let’s say you want to build a content site where different &lt;strong&gt;creators&lt;/strong&gt; can create &lt;strong&gt;posts&lt;/strong&gt;, you’d have a relational database with two tables &lt;strong&gt;Creator&lt;/strong&gt; and &lt;strong&gt;Post&lt;/strong&gt; that may look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WhlF2AWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AzTLAQfTO-wxZDMXgvOQ3Fg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WhlF2AWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AzTLAQfTO-wxZDMXgvOQ3Fg.png" alt="A spreadsheet with two tables, Creator with the rows ID and Name and Post with the rows ID, Title, Type and Body"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your creator table has an &lt;em&gt;ID&lt;/em&gt; and &lt;em&gt;Name&lt;/em&gt; column for every item that gets created and your post table has an &lt;em&gt;ID&lt;/em&gt;, &lt;em&gt;Title&lt;/em&gt;, &lt;em&gt;Type&lt;/em&gt; and &lt;em&gt;Body&lt;/em&gt; column for every item. In each column, the primary key will be the &lt;em&gt;ID&lt;/em&gt; column since that’s going to be the unique identifier for each record. The &lt;a href="https://www.bbc.co.uk/bitesize/guides/ztsvb9q/revision/5"&gt;primary key&lt;/a&gt; is important when creating associations because it acts as the &lt;a href="https://www.bbc.co.uk/bitesize/guides/ztsvb9q/revision/5"&gt;foreign key&lt;/a&gt; in the associated table.&lt;/p&gt;

&lt;p&gt;Now we need to decide what kind of relationship the two tables will have with each other since we’d likely want to know which creators created which posts. There are a few different kinds of associations you can create but I’ll only touch on two.&lt;/p&gt;

&lt;h3&gt;
  
  
  has_many
&lt;/h3&gt;

&lt;p&gt;A has_many association, says one item in a table can be associated with many items in another table. For example, if our system is a standard content creation system then a &lt;strong&gt;creator&lt;/strong&gt; can have many &lt;strong&gt;posts&lt;/strong&gt; since one &lt;strong&gt;creator&lt;/strong&gt; can create many &lt;strong&gt;posts&lt;/strong&gt; in which case, the association in Rails would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Creator&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:posts&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:creator&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our database would look like:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5i8fzcDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUvKD65Tc6EPzhXAK3IsoDA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5i8fzcDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUvKD65Tc6EPzhXAK3IsoDA.png" alt="A spreadsheet with two tables, Creator with the rows ID and Name and Post with the rows ID, Title, Type, Body and Creator_ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;creator_id&lt;/code&gt; would be pulled from the &lt;code&gt;id&lt;/code&gt; column, which is the primary key in the &lt;strong&gt;creator&lt;/strong&gt; table and act as a foreign key in the &lt;strong&gt;post&lt;/strong&gt; table. So if you wanted to find all the posts created by Tiffany Pollard, you’d do a search on the &lt;strong&gt;post&lt;/strong&gt; table where the &lt;code&gt;creator_id&lt;/code&gt; matches Tiffany Pollard’s &lt;code&gt;id&lt;/code&gt; in the &lt;strong&gt;creator&lt;/strong&gt; table.&lt;/p&gt;
&lt;h3&gt;
  
  
  has_one
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;has_one&lt;/code&gt; relationship says one item in a table can only be associated with one item in another table, no more than one. We may want to create a system where a &lt;strong&gt;creator&lt;/strong&gt; can only ever create one &lt;strong&gt;post&lt;/strong&gt; in which case, our Rails code would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Creator&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:creator&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;creator&lt;/strong&gt; &lt;code&gt;has_one&lt;/code&gt; post and a post &lt;code&gt;belongs_to&lt;/code&gt; a &lt;strong&gt;creator&lt;/strong&gt;. The database looks the same as before:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5i8fzcDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUvKD65Tc6EPzhXAK3IsoDA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5i8fzcDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUvKD65Tc6EPzhXAK3IsoDA.png" alt="A spreadsheet with two tables, Creator with the rows ID and Name and Post with the rows ID, Title, Type, Body and Creator_ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And just like with &lt;code&gt;has_many&lt;/code&gt; the &lt;code&gt;creator_id&lt;/code&gt; is the foreign key for the creator’s &lt;code&gt;id&lt;/code&gt; in the post table.&lt;/p&gt;

&lt;p&gt;Okay, so now onto the problem.&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;In Rails when you create a &lt;code&gt;has_one&lt;/code&gt; association, understandably the assumption is that a &lt;strong&gt;creator&lt;/strong&gt; can only ever have one &lt;strong&gt;post&lt;/strong&gt;. So what happens when a &lt;strong&gt;creator&lt;/strong&gt; tries to create another &lt;strong&gt;post&lt;/strong&gt;? You’d hope that it’d check to see if a post exists and ask the creator if they want to replace the post or just replace the post with the assumption that that’s the intention of the creator. But that’s not what happens, instead, you get this error:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u1-QJjlm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2ANBIfqCesY82KGPb0P4jLyQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u1-QJjlm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2ANBIfqCesY82KGPb0P4jLyQ.png" alt='A rails error message that reads "Failed to remove the existing associated post. The record failed to save after its foreign key was set to nil.'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a common error with &lt;code&gt;has_one&lt;/code&gt; and is summed up nicely in this &lt;a href="https://github.com/rails/rails/issues/17325"&gt;issue&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is because prior to deleting, the foreign key of the target association is set to nil and a save operation is performed on the target.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s unclear &lt;em&gt;why&lt;/em&gt; this happens, if you go through the issue you’ll notice it was created in 2014 and the discussion is still ongoing. It seems this started out as a bug but may have evolved to become the desired functionality.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6V0ONV9O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AS57ZWGL44S9x3ayM" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6V0ONV9O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AS57ZWGL44S9x3ayM" alt="A small dog wearing glasses and a shirt using a laptop"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a number of ways to fix this and it all depends on your system. Essentially, you want to make sure the old association is deleted before you try to create a new one. So, you can do this in your model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Creator&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dependent: :destroy&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:creator&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or in the method where you create your resource (either in your controller or specific lib file) you can run something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;creator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Creator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;creator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before you create any post. Andy Croll from Coverage Book recommends &lt;a href="https://andycroll.com/ruby/be-careful-assigning-to-has-one-relations/"&gt;rolling things up in a transaction&lt;/a&gt; and there are more suggestions in the &lt;a href="https://github.com/rails/rails/issues/17325"&gt;GitHub issue&lt;/a&gt; too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://andycroll.com/ruby/be-careful-assigning-to-has-one-relations/"&gt;Be Careful Assigning has_one Relations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/issues/17325"&gt;Building a has_one association fails on save if target has a validation on foreign_key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bbc.co.uk/bitesize/guides/ztsvb9q/revision/5"&gt;BBC Bitesize: Introducing Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://guides.rubyonrails.org/association_basics.html"&gt;Rails ActiveRecord Associations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>webdev</category>
      <category>database</category>
    </item>
    <item>
      <title>Making an AR Game with AFrame</title>
      <dc:creator>Ada Rose Cannon 🏳️‍🌈</dc:creator>
      <pubDate>Thu, 14 Jan 2021 16:57:37 +0000</pubDate>
      <link>https://dev.to/samsunginternet/making-an-ar-game-with-aframe-1pe6</link>
      <guid>https://dev.to/samsunginternet/making-an-ar-game-with-aframe-1pe6</guid>
      <description>&lt;h1&gt;
  
  
  Making an AR Game with AFrame
&lt;/h1&gt;

&lt;p&gt;Using AFRAME, THREE.js and WebXR to build a game during a 4.5hr live stream.&lt;/p&gt;

&lt;p&gt;Here is a .gif (jiff?) of the final game, &lt;a href="https://ada.is/basketball-demo/" rel="noopener noreferrer"&gt;click here to play the game&lt;/a&gt;. It uses the &lt;a href="https://github.com/immersive-web/dom-overlays/blob/master/explainer.md" rel="noopener noreferrer"&gt;WebXR DOM Overlay API&lt;/a&gt;, and the &lt;a href="https://github.com/immersive-web/hit-test/blob/master/hit-testing-explainer.md" rel="noopener noreferrer"&gt;WebXR Hit Test API&lt;/a&gt;. So right now the best way to play it is in Mobile Chrome or &lt;a href="https://play.google.com/store/apps/details?id=com.sec.android.app.sbrowser.beta&amp;amp;hl=en_GB&amp;amp;gl=US" rel="noopener noreferrer"&gt;Samsung Internet Beta&lt;/a&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%2F2092%2F1%2AuxubAT7y_4V7U0cUCtEiQg.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%2F2092%2F1%2AuxubAT7y_4V7U0cUCtEiQg.gif" alt="A virtual ball being shot into a virtual basketball hoop."&gt;&lt;/a&gt;&lt;em&gt;A virtual ball being shot into a virtual basketball hoop.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you want to watch all four-plus hours of the live stream the URLs are here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Part 1: &lt;a href="https://t.co/oDXGh3jtJc?amp=1" rel="noopener noreferrer"&gt;https://youtu.be/ee7PPDmPuqY&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Part 2: &lt;a href="https://t.co/YLcBGMvRs4?amp=1" rel="noopener noreferrer"&gt;https://youtu.be/RWFQ2FqEMi4&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Part 3: &lt;a href="https://t.co/ulYQbGTudB?amp=1" rel="noopener noreferrer"&gt;https://youtu.be/5XTDOcMU3Vg&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to just look through the source code here it is:&lt;br&gt;
&lt;a href="https://github.com/AdaRoseCannon/basketball-demo" rel="noopener noreferrer"&gt;&lt;strong&gt;AdaRoseCannon/basketball-demo&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Playbasket ball in AR with Aframe and the WebXR device API GitHub is home to over 50 million developers working…&lt;/em&gt; github.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was my first time live streaming a whole project from start to finish. It was fun I think I would do it again for small projects like this. In this blog post I will talk about what tools I used to make it and some of the tricks that went into it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting up AFrame
&lt;/h3&gt;

&lt;p&gt;First thing first is to create a new HTML file. index.html and put in some HTML boilerplate. I do this in VSCode using the &lt;a href="https://docs.emmet.io/abbreviations/" rel="noopener noreferrer"&gt;Emmet Abbreviation&lt;/a&gt; ! to auto-fill some basic HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My AR Game&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next to add the AFrame script I copy and paste the script tag from the &lt;a href="https://aframe.io/docs/1.1.0/introduction/" rel="noopener noreferrer"&gt;AFrame docs&lt;/a&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;script src="[https://aframe.io/releases/1.1.0/aframe.min.js](https://aframe.io/releases/1.1.0/aframe.min.js)"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And paste the AFrame hello world into the body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;scene&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;box&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-1 0.5 -3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 45 0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#4CC3D9&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a-box&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;sphere&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 1.25 -5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.25&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#EF2D5E&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a-sphere&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cylinder&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1 0.75 -3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#FFC65D&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a-cylinder&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;plane&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 0 -4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-90 0 0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#7BC8A4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a-plane&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;sky&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ECECEC&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a-sky&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a-scene&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;To test it I start a local http server to let me display it on my computer. I use the node &lt;a href="https://www.npmjs.com/package/http-server" rel="noopener noreferrer"&gt;http-server module&lt;/a&gt;. If you don’t have node environment to hand a couple of other options are &lt;a href="https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=en" rel="noopener noreferrer"&gt;the Chrome Web Server extension&lt;/a&gt; or building it on a website like &lt;a href="https://glitch.com" rel="noopener noreferrer"&gt;glitch.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WebXR requires a secure origin to run. Secure origins usually begin with https:// a special secure origin is &lt;a href="http://localhost" rel="noopener noreferrer"&gt;http://localhost&lt;/a&gt; which lets you access local a http server.&lt;/p&gt;

&lt;p&gt;If you are using Glitch you can just open the URL on the your phone to test it.&lt;/p&gt;

&lt;p&gt;Unfortunately the requirement for a secure origin makes things tricky for testing a local server on external devices. Normally I would access the server on my development computer via IP address like so: &lt;a href="http://192.168.0.10:8080" rel="noopener noreferrer"&gt;http://192.168.0.10:8080&lt;/a&gt; but since it’s not a secure origin it can’t be used for WebXR.&lt;/p&gt;

&lt;p&gt;To test it on my phone there are two options which work well, the most convenient option is to plug in my phone using USB and use Chrome’s remote debugging to forward the port of the http server. Open chrome://inspect in Chrome to access this feature:&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%2F2000%2F1%2ASs-HR1WZoUBXdahUHCsLzw.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%2F2000%2F1%2ASs-HR1WZoUBXdahUHCsLzw.png" alt="chrome://inspect"&gt;&lt;/a&gt;&lt;em&gt;chrome://inspect&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once that is set up you can then open up &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; (replace 8080 with whatever port you are using) on your phone and test like you would on your computer.&lt;/p&gt;

&lt;p&gt;During my live streams I couldn’t get this working since I was using my phone’s USB-C port to capture the HDMI. So I used &lt;a href="https://ngrok.com/" rel="noopener noreferrer"&gt;https://ngrok.com/&lt;/a&gt; to get a real https: enabled URL for my local server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enabling AR features
&lt;/h3&gt;

&lt;p&gt;The first thing to notice when you try AR in our AFRame scene is that you’ll see through the device camera briefly before it gets obscured when the scene gets shown. This is because the  element covers the whole scene.&lt;/p&gt;

&lt;p&gt;To solve this we’ll add a new AFrame component to hide objects when the scene goes into AR. This code is from work done by &lt;a href="https://github.com/aframevr/aframe/pull/4356/files" rel="noopener noreferrer"&gt;Klaus Weidner in one of the AFrame demos&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;AFRAME&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hide-in-ar-mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sceneEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;enter-vr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sceneEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ar-mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sceneEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;exit-vr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I included this snippet in a little library of useful components I copy from project to project. As well as some other useful parts so I will just add that script to the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"[https://ada.is/basketball-demo/ar-components.js](https://ada.is/basketball-demo/ar-components.js)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds a hide-in-ar-mode component and an ar-hit-test we can use in Aframe. We add the hide-in-ar-mode component to HTML elements I want to hide in AR such as the  so it now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a-sky&lt;/span&gt; &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"#ECECEC"&lt;/span&gt; &lt;span class="na"&gt;hide-in-ar-mode&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/a-sky&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other issue is the scale. The AFrame hello world example is designed for VR. In VR where physically large scenes work well because you can take advantage of the unlimited space. In the AFrame Hello World Example the content is placed 5 meters from the user and is 2.5m tall. This is very large and looks impressive in VR but in AR is much too big to fit in many people’s real environment.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  When designing AR scenes, try to avoid having the content larger than 0.5m to enable people to fit it in their environment.
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;p&gt;When designing AR scenes, try to avoid having the content larger than 0.5m to enable people to fit it in their environment. I say this as someone who lives in a small apartment.&lt;/p&gt;

&lt;p&gt;The times when you want to break this rule is when the AR scene is designed to only be used outside where space is more available or when the virtual object is a stand in for a real object which has specific dimensions. Such as if they are buying a particular piece of furniture and want to see how well it fits in their house.&lt;/p&gt;

&lt;p&gt;To update the scene I made all the objects in the scene 10% of their original size. All of the units in WebXR and AFrame are in meters so I turned 1.25m into 0.125m (12.5cm or about 6 inches.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding hit testing
&lt;/h3&gt;

&lt;p&gt;Hit testing allows you cast rays from the virtual content into the real world. So you can place virtual objects inline with real world objects such as the floor, tables and walls.&lt;/p&gt;

&lt;p&gt;It will get you both the position and normal of where it hits letting objects be placed on services both vertical and horizontal.&lt;/p&gt;

&lt;p&gt;The hit-test feature is one which is not available by default in WebXR because it lets you get additional information about a user’s environment.&lt;/p&gt;

&lt;p&gt;But you can request it when the XR session is started in AFrame you add it to your  element using the webxr component like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a-scene&lt;/span&gt; &lt;span class="na"&gt;webxr=&lt;/span&gt;&lt;span class="s"&gt;"optionalFeatures: hit-test;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To assist in how it’s used I made a component to help with it in the library I mentioned earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"[https://ada.is/basketball-demo/ar-components.js](https://ada.is/basketball-demo/ar-components.js)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ar-hit-test component will continuously do hit-testing using the most relevant user input available assisting you to build something which works on a variety of hardware. Such as it will default from using the headset position but will use a VR controller or hand tracking if it is available.&lt;/p&gt;

&lt;p&gt;Wherever the hit lands it will place the object. This makes it handy for being a targeting reticle in AR.&lt;/p&gt;

&lt;p&gt;We’ll make a 20cm square to use for the guiding reticle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a-plane&lt;/span&gt;
 &lt;span class="na"&gt;rotation=&lt;/span&gt;&lt;span class="s"&gt;"-90 0 0"&lt;/span&gt;
 &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"0.2"&lt;/span&gt;
 &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"0.2"&lt;/span&gt;
 &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./arrow.png"&lt;/span&gt;
 &lt;span class="na"&gt;material=&lt;/span&gt;&lt;span class="s"&gt;"transparent:true;"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/a-plane&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F2000%2F1%2Aapen6MoiJxGX4BeNUjNNlw.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%2F2000%2F1%2Aapen6MoiJxGX4BeNUjNNlw.png" alt="arrow.png"&gt;&lt;/a&gt;&lt;em&gt;arrow.png&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Like &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; is for HTML for AFrame it is &lt;code&gt;&amp;lt;a-entity&amp;gt;&lt;/code&gt;. This is a plain element with no additional properties such as 3D models. We will make a new  which uses the ar-hit-test component to be positioned by hit-testing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a-entity&lt;/span&gt; &lt;span class="na"&gt;ar-hit-test=&lt;/span&gt;&lt;span class="s"&gt;"doHitTest:false"&lt;/span&gt; &lt;span class="na"&gt;visible=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

Reticle HTML goes here ...

&lt;span class="nt"&gt;&amp;lt;/a-entity&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ve also made it invisible since the ar-hit-test component will make it visible again when it’s able to do hit-testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Basketball Hoop
&lt;/h3&gt;

&lt;p&gt;Now we have some way of getting the position of real world objects we want to create the hoop to go on the wall.&lt;/p&gt;

&lt;p&gt;Objects placed on surfaces using hit testing have their y-axis (the up and down axis) aligned with the &lt;a href="https://en.wikipedia.org/wiki/Normal_(geometry)" rel="noopener noreferrer"&gt;normal&lt;/a&gt; of the surface they are being placed on. This means that objects placed on the floor should appear pretty normal but on surfaces like walls or ceilings they will get rotated. The objects are usually also rotated around this normal to face the hit-test source but this behaviour is not in the spec and so may vary.&lt;/p&gt;

&lt;p&gt;Since an object placed on the wall will be rotated 90 degrees we will start it off with some initial rotation as we design it. So the encapsulating entity #hoop will have rotation="90 0 0" which is similar to an object placed on a wall. If we were placing it on the floor a rotation of 0 0 0 would suffice. This rotation will be reset when we place the object against the wall to what ever the orientation of the normal of the wall is.&lt;/p&gt;

&lt;p&gt;The hoop will be made of 3 simple shapes, a plane for the back board a torus for the hoop and an open ended cone for the net:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a-entity&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hoop"&lt;/span&gt; &lt;span class="na"&gt;rotation=&lt;/span&gt;&lt;span class="s"&gt;"90 0 0"&lt;/span&gt; &lt;span class="na"&gt;position=&lt;/span&gt;&lt;span class="s"&gt;"0 2 -1.8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 

    &lt;span class="nt"&gt;&amp;lt;a-torus&lt;/span&gt; &lt;span class="na"&gt;scale=&lt;/span&gt;&lt;span class="s"&gt;"0.6 0.6 0.6"&lt;/span&gt; &lt;span class="na"&gt;position=&lt;/span&gt;&lt;span class="s"&gt;"0 0.173 -0.1"&lt;/span&gt; &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"#43A367"&lt;/span&gt; &lt;span class="na"&gt;radius=&lt;/span&gt;&lt;span class="s"&gt;"0.25"&lt;/span&gt; &lt;span class="na"&gt;radius-tubular=&lt;/span&gt;&lt;span class="s"&gt;"0.005"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/a-torus&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;a-plane&lt;/span&gt;
     &lt;span class="na"&gt;scale=&lt;/span&gt;&lt;span class="s"&gt;"0.6 0.6 0.6"&lt;/span&gt;
     &lt;span class="na"&gt;position=&lt;/span&gt;&lt;span class="s"&gt;"0 0 -0.3"&lt;/span&gt;
     &lt;span class="na"&gt;rotation=&lt;/span&gt;&lt;span class="s"&gt;"-90 0 0"&lt;/span&gt;
     &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"0.9"&lt;/span&gt;
     &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"0.9"&lt;/span&gt;
     &lt;span class="na"&gt;material=&lt;/span&gt;&lt;span class="s"&gt;"transparent: true; side: double;"&lt;/span&gt;
     &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./backboard.png"&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&amp;lt;/a-plane&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;a-cone&lt;/span&gt; &lt;span class="na"&gt;scale=&lt;/span&gt;&lt;span class="s"&gt;"0.6 0.6 0.6"&lt;/span&gt; &lt;span class="na"&gt;position=&lt;/span&gt;&lt;span class="s"&gt;"0 0.173 -0.010"&lt;/span&gt; &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"tomato"&lt;/span&gt; &lt;span class="na"&gt;radius-bottom=&lt;/span&gt;&lt;span class="s"&gt;"0.25"&lt;/span&gt; &lt;span class="na"&gt;radius-top=&lt;/span&gt;&lt;span class="s"&gt;"0.3"&lt;/span&gt; &lt;span class="na"&gt;material=&lt;/span&gt;&lt;span class="s"&gt;"side: double; opacity:0.5; transparent: true;"&lt;/span&gt; &lt;span class="na"&gt;geometry=&lt;/span&gt;&lt;span class="s"&gt;"height: 0.29; openEnded: true"&lt;/span&gt; &lt;span class="na"&gt;rotation=&lt;/span&gt;&lt;span class="s"&gt;"90 0 0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/a-cone&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/a-entity&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The end result is simple but should be clear what is.&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%2F2000%2F1%2A5TaP9YnC8N6TLK4lHyLKrA.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%2F2000%2F1%2A5TaP9YnC8N6TLK4lHyLKrA.png" alt="The basketball hoop created by the code earlier"&gt;&lt;/a&gt;&lt;em&gt;The basketball hoop created by the code earlier&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Positioning the hoop
&lt;/h3&gt;

&lt;p&gt;We want the player to be able to position the hoop on their wall. We can get their chosen position by copying the location from the reticle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reticle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[ar-hit-test]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;positionHoop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nx"&gt;hoop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;visible&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;hoop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;hoop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rotation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rotation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;reticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;select&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;positionHoop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This very simple function will make the hoop visible and position the hoop at the same position and rotation as the reticle when a select is made. This naive function will often make the hoop a bit crooked though as it will be tilted to face the hit-test origin but lining it up is hard. So we will need to do some Vector Math to ensure the z direction of the hoop lines up with the y-axis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;upVector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tempVector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tempQuaternion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;positionHoop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nx"&gt;hoop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;hoop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;visible&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;tempVector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;tempVector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;applyQuaternion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object3D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quaternion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;tempQuaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFromUnitVectors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tempVector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upVector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;hoop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object3D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multiplyQuaternions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tempQuaternion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object3D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quaternion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This slightly more complicated function will work out the Quaternion rotation needed to rotate the reticle into an upright position. It will then set the quaternion rotation of the hoop to multiplication of that rotation with the reticle’s rotation. Resulting in a hoop that is facing the right way but twisted slightly so that it points up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding physics to the scene
&lt;/h3&gt;

&lt;p&gt;Physics is handled by the very useful &lt;a href="https://github.com/n5ro/aframe-physics-system" rel="noopener noreferrer"&gt;aframe-physics-system&lt;/a&gt; this allows you to make the objects in the scene behave in physically realistic ways.&lt;/p&gt;

&lt;p&gt;There are two types of physics objects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Static Bodies, these do not move or react to being hit by other objects they effectively have infinite mass and are unaffected by gravity. They are cheap to use but cannot move. Anything that should not move should be a static body such as Floors and Walls and in our case the basketball hoop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dynamic Bodies, these have mass and will fall with constant acceleration under gravity. They can bounce off static bodies or collide with other dynamic bodies. The only dynamic body in the scene is the ball itself.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To set up the physics system we will include the script after the A-Frame script and add the physics component to our scene element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/gh/n5ro/aframe-physics-system@v4.0.1/dist/aframe-physics-system.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

...

&lt;span class="nt"&gt;&amp;lt;a-scene&lt;/span&gt; &lt;span class="na"&gt;physics=&lt;/span&gt;&lt;span class="s"&gt;"debug: false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To help setting up your scene it can be worth while to set debug to true so that you can see the shapes it has made outlined in red.&lt;/p&gt;

&lt;p&gt;Next we add a sphere with the dynamic-body component to be the ball:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a-sphere&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"ball"&lt;/span&gt; &lt;span class="na"&gt;dynamic-body&lt;/span&gt; &lt;span class="na"&gt;radius=&lt;/span&gt;&lt;span class="s"&gt;"0.1"&lt;/span&gt; &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"orange"&lt;/span&gt; &lt;span class="na"&gt;position=&lt;/span&gt;&lt;span class="s"&gt;"0.1 2.36 -1.5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/a-sphere&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we reload the page the ball should fall indefinitely.&lt;/p&gt;

&lt;p&gt;The next step is to add static-body to the floor plane so that something can stop the ball, I also made it much larger as the ball will roll when it hits it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a-plane&lt;/span&gt;
    &lt;span class="na"&gt;rotation=&lt;/span&gt;&lt;span class="s"&gt;"-90 0 0"&lt;/span&gt;
    &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"20"&lt;/span&gt;
    &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"20"&lt;/span&gt;
    &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"#43A367"&lt;/span&gt;
    &lt;span class="na"&gt;static-body&lt;/span&gt;
    &lt;span class="na"&gt;hide-in-ar-mode&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/a-plane&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we play the game we want to interact with the hoop. So next we will add static-body to the backboard plane.&lt;/p&gt;

&lt;p&gt;What do we do about the hoop? This is a lot more complicated. The hoop is a convex object it has a pretty complex topology and the 3D model has many vertices which makes the physics very expensive.&lt;/p&gt;

&lt;p&gt;The trick here is to have an invisible torus with as few polygons as we can manage, we make it a static body but make it invisible and place it on top of the high resolution model. This is a common trick in video games to have the physics objects with much simpler geometry than the visible objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a-torus&lt;/span&gt; &lt;span class="na"&gt;scale=&lt;/span&gt;&lt;span class="s"&gt;"0.6 0.6 0.6"&lt;/span&gt; &lt;span class="na"&gt;static-body=&lt;/span&gt;&lt;span class="s"&gt;"shape: mesh;"&lt;/span&gt; &lt;span class="na"&gt;position=&lt;/span&gt;&lt;span class="s"&gt;"0 0.173 -0.1"&lt;/span&gt; &lt;span class="na"&gt;visible=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="na"&gt;radius=&lt;/span&gt;&lt;span class="s"&gt;"0.27"&lt;/span&gt; &lt;span class="na"&gt;radius-tubular=&lt;/span&gt;&lt;span class="s"&gt;"0.02"&lt;/span&gt; &lt;span class="na"&gt;geometry=&lt;/span&gt;&lt;span class="s"&gt;"radius: 0.29; segmentsRadial: 5; segmentsTubular: 12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/a-torus&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By having the static objects of the hoop inside the hoop entity they will be kept inline with the visible objects.&lt;/p&gt;

&lt;p&gt;AFrame Physics System also has a JavaScript API for detecting when two objects collide or setting velocities of objects. It is available on the body property of the entity we want to control as long it is a static or dynamic body.&lt;/p&gt;

&lt;p&gt;If we want to set the position and velocity of an object such as the ball we use this method. Here is how we launch the ball from the currently active controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ball&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;reticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;select&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Set the ball location to the controller position&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pose&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// {x, y, z}&lt;/span&gt;

  &lt;span class="c1"&gt;// Have an initial velocity vector of 5ms into the screen&lt;/span&gt;
  &lt;span class="nx"&gt;tempVector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Set our velocity vector direction to the controller orientation&lt;/span&gt;
  &lt;span class="c1"&gt;// {x, y, z, w}&lt;/span&gt;
  &lt;span class="nx"&gt;tempVector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;applyQuaternion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orientation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// set the velocity of the ball to our velocity vector&lt;/span&gt;
  &lt;span class="nx"&gt;ball&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;velocity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tempVector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dom Overlay
&lt;/h3&gt;

&lt;p&gt;The last thing we need is to make some UI so that the user can say when they have set the hoop position and are ready to play. We can build a normal HTML interface for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"overlay"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Welcome To Basketball&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"overlay-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"instructions"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Place the basket along a wall&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: flex; justify-content: space-between; align-self: stretch;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"go-button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Ready to Play!&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"exit-button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Stop AR&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can use it by declaring it on the WebXR component on the scene object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a-scene&lt;/span&gt; &lt;span class="na"&gt;webxr=&lt;/span&gt;&lt;span class="s"&gt;"optionalFeatures: hit-test, dom-overlay; overlayElement:#overlay;"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using real HTML buttons and text has many benefits for the user such as working with accessibility tools, being more readable. It can be styled with regular CSS and can be coded with normal JavaScript.&lt;/p&gt;

&lt;p&gt;Something to bear in mind though is that when the user taps on DOM Overlay Elements they will fire input events such as 'click' 'mousedown' and 'touchstart' events as usual but in addition will fire WebXR 'select' events first!&lt;/p&gt;

&lt;p&gt;So you may need to use something like a setTimeout in your 'select' events to ensure that a button has not been pushed if you are waiting for input from the HTML buttons.&lt;/p&gt;

&lt;p&gt;You can detect support for DOM Overlay by looking for xrsession.domOverlayState.type . If domOverlayState is not set then domOverlay is not present in the browser. If type is not set then the current hardware/browser configuration does not support DOM Overlay so you can use the following function to detect it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hasDomOverlay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xrsession&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;xrsession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOverlayState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// DOM Overlay is not supported&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;xrsession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOverlayState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// DOM Overlay is not in use&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using DOM Overlay for essential paths through the code then you can use this to detect availability and provide fall back behaviors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read the source code to the finished demo
&lt;/h3&gt;

&lt;p&gt;Here is the source code to the demo, I hope this guide helps you make sense of it and some of the decisions that were made. If you have further questions feel free to reach out to me through Twitter.&lt;/p&gt;

&lt;p&gt;Thank you so much for reading!&lt;br&gt;
&lt;a href="https://github.com/AdaRoseCannon/basketball-demo/blob/main/index.html" rel="noopener noreferrer"&gt;&lt;strong&gt;AdaRoseCannon/basketball-demo&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Playbasket ball in AR with Aframe and the WebXR device API - AdaRoseCannon/basketball-demo&lt;/em&gt; github.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aframe</category>
      <category>webxr</category>
      <category>ar</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Promises for Rubyists</title>
      <dc:creator>Lola</dc:creator>
      <pubDate>Mon, 07 Dec 2020 10:57:42 +0000</pubDate>
      <link>https://dev.to/samsunginternet/promises-for-rubyists-2loe</link>
      <guid>https://dev.to/samsunginternet/promises-for-rubyists-2loe</guid>
      <description>&lt;h1&gt;
  
  
  The Soundtrack
&lt;/h1&gt;

&lt;p&gt;I tried to write a post about JavaScript Promises using Ciara - Promise, but it didn't work so instead have this genre-agnostic playlist of 10 songs with the title Promise. Don't let my hard work be in vain &amp;amp; have a listen.&lt;br&gt;
&lt;iframe width="100%" height="380px" src="https://open.spotify.com/embed/playlist/6mvCLTreLdT2gBMTwUeTKJ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  The Background
&lt;/h1&gt;

&lt;p&gt;JavaScript and Ruby are both single-threaded programming languages, they can really only do one thing at a time, in a particular order. This also means they're both synchronous. They run in a queue-like way, the first operation or function to get called is the first to be performed before any other operation is performed, this presents a problem the moment you want to do anything that requires multi-tasking. Both languages have workarounds, modules, gems and in-built features that can allow you to write asynchronous code, e.g. JavaScript's &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API"&gt;Web Workers&lt;/a&gt; or background jobs in Ruby. JavaScript also has promises, the topic of today, which Ruby doesn't have an in-built match for at the moment, so I'm going to try my best to recreate what this could look like.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Promise
&lt;/h1&gt;

&lt;p&gt;It's a commitment to give you &lt;em&gt;something&lt;/em&gt; later, it'll either be the thing you ask for or an error but you'll definitely get something.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Essentially, a promise is a returned object to which you attach callbacks, instead of passing callbacks into a function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;-&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Callbacks in Ruby
&lt;/h3&gt;

&lt;p&gt;In Ruby, we really mainly deal with callbacks in the context of Rails (or other web framework) when we're manipulating objects during their creation phase. You might have used a &lt;code&gt;before_create: :do_thing&lt;/code&gt; in a model, this is generally what callbacks are in Rails (not necessarily Ruby), and there are a &lt;a href="https://guides.rubyonrails.org/active_record_callbacks.html"&gt;list of them&lt;/a&gt;. But using plain old Ruby, you'd have a method that you could pass a block to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
     &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"the total is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The callback here is the block we pass to &lt;code&gt;add_one(5)&lt;/code&gt; which is then called with our &lt;code&gt;yield&lt;/code&gt; in the definition of the method. So here we're passing the callback to the method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Callbacks in JavaScript
&lt;/h3&gt;

&lt;p&gt;Unlike Ruby, JavaScript functions can accept functions as arguments but not blocks which means you'd create dedicated callback functions in a JS context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the total is ${total}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getTotal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're also passing the callback to the function, similar to the Ruby implementation. This is synchronous since a blocking operation (the &lt;code&gt;addOne&lt;/code&gt;) needs to happen first before the callback can happen.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementation
&lt;/h1&gt;

&lt;p&gt;There isn't a native way to write promises in Ruby but just to illustrate the functionality, imagine being able to send data between your controller and view without refreshing the page in Ruby, with no JavaScript. It's the stuff dreams are made of but in the real world we need JavaScript.&lt;/p&gt;

&lt;p&gt;I've been working on the &lt;a href="https://medium.com/samsung-internet-dev/samsung-the-global-goals-web-debuts-f8cdae4ec21d"&gt;Samsung's Global Goals&lt;/a&gt; PWA and in this I've had to use promises to interact with Stripe and the Payment Request API. Let's see a real world example of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fetchPaymentIntentClientSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchedPaymentIntentCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/fetchPaymentIntent/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientSecretObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchedPaymentIntentCS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;clientSecretObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="nx"&gt;fetchPaymentIntentClientSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;confirmPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paymentRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;fetchPaymentIntentClientSecret&lt;/code&gt; function is defined using the keyword &lt;code&gt;async&lt;/code&gt;, in the function we make a call to the server using &lt;code&gt;await&lt;/code&gt; and &lt;code&gt;fetch&lt;/code&gt; this call then gives us back some data which we return. The &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; functions are important here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; keywords enable asynchronous, promise-based behaviour to be written in a asynchronous style, avoiding the need to explicitly configure promise chains.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The function could also be written like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fetchPaymentIntentClientSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/fetchPaymentIntent/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// response.json also returns a promise since it has to wait for the response to finish before it can parse it&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientSecretObj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;clientSecretObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// extract the thing you need from the response&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchPaymentIntentCSPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fetchPaymentIntentClientSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;confirmPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paymentRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that &lt;code&gt;fetchPaymentIntentClientSecret&lt;/code&gt; actually returns a promise. &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; are just syntactic sugar for the promises syntax. Using these keywords together, along with &lt;code&gt;fetch&lt;/code&gt; allows us to make the asynchronous call to the server. So when we actually call the function, because it's a promise, we can chain the callbacks and really take advantage of the asynchronous nature. The &lt;code&gt;clientSecret&lt;/code&gt; is returned from the server and we can pass that to the next function that needs it if the call is successful and if it's not, we can log the error instead.&lt;/p&gt;

&lt;p&gt;All without the page being refreshed or modified.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Note
&lt;/h3&gt;

&lt;p&gt;You might have seen promise syntax that looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;myFancyFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// does something&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFancyFuncPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myFancyFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you're wondering why I haven't done that here. Well, the syntax is different if you're working with a promise-based API, which I am. In our example &lt;code&gt;fetch&lt;/code&gt; returns a promise as does &lt;code&gt;response.json&lt;/code&gt; so we need to treat them as such. &lt;code&gt;new Promise&lt;/code&gt; is used to make promises out of async APIs which are not promise based, e.g. the callback based functions we defined earlier.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why?
&lt;/h1&gt;

&lt;p&gt;Within the context web development, promises are unique to JavaScript in that they're native. Coming from a Ruby background I found them strange, why not just do these things in a background job? But honestly, a small action like retrieving a client secret doesn't need to be done in a job (and probably shouldn't be) and it's probably not the best user experience to reload the page just to get a client secret, especially if the user hasn't triggered it.&lt;/p&gt;

&lt;p&gt;Promises can also be quite complex to get your head around, this post is a primer but I'd encourage you to read more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Using Promises)[&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;(Promise)[&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>ruby</category>
    </item>
    <item>
      <title>HTML and Templates &amp; JavaScript Template Literals</title>
      <dc:creator>Ada Rose Cannon 🏳️‍🌈</dc:creator>
      <pubDate>Tue, 27 Oct 2020 09:01:45 +0000</pubDate>
      <link>https://dev.to/samsunginternet/html-and-templates-javascript-template-literals-1l0j</link>
      <guid>https://dev.to/samsunginternet/html-and-templates-javascript-template-literals-1l0j</guid>
      <description>&lt;h1&gt;
  
  
  HTML and Templates &amp;amp; JavaScript Template Literals
&lt;/h1&gt;

&lt;p&gt;HTML and Templates &amp;amp; JavaScript Template Literals&lt;/p&gt;

&lt;p&gt;HTML in the Web is often made of reusable components, composed by templates, making it convenient to edit the different parts that make up a website. There are many templating languages used in the web such as handlebars, Pug, Vue and JSX; these are primarily used for composing HTML. Modern JavaScript has templating syntax built in which can use for all kinds of purposes including composing HTML.&lt;/p&gt;

&lt;p&gt;In this post I will introduce the JavaScript syntax for templating and then show how it can be used in the real world for sanitising HTML and introducing some of the frameworks which use template literals for their templating.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals"&gt;Template Literals&lt;/a&gt; are a really nice JavaScript feature you may not have used much yet, they look a bit like strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;Hello World&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can include new lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;Hello
World&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use the dollar-curly-brace ${} syntax to inject variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ada&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works really well when combined with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions"&gt;Arrow Function Expressions&lt;/a&gt; to make templating functions, which turn the arguments into a string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messageFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messageFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ada&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tagged Template Literals
&lt;/h3&gt;

&lt;p&gt;You can put a tag on a template to transform the template before it gets turned into a string.&lt;/p&gt;

&lt;p&gt;The tag is a function which is called with the first argument being an array of the rest of the arguments are the values of the place holders. In the example below we use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters"&gt;rest parameter&lt;/a&gt; to put all of the place holder arguments into an array.&lt;/p&gt;

&lt;p&gt;There is always one more string than the number of placeholders. You can reassemble the output by interleaving these Arrays such that for a template with N placeholders the output is:&lt;/p&gt;

&lt;p&gt;strings[0] + placeholders[0] + strings[1] + placeholders[1] + … + strings[N] + placeholders[N] + strings[N+1];&lt;/p&gt;

&lt;p&gt;This is what is looks like in JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;myTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;N&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myTag&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt; world &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function is equivalent to the String.raw function which is the default behaviour for template literals.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;Hello &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt; world &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use String.raw inside your custom template tag to regenerate a string. In the example below we check the input to make sure it’s a string then use String.raw to output the data as a String.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;myTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your tagged template literal doesn’t have to return a String it can return what ever you need, here is a very simple tag which measures the length of the input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;myTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HTML &amp;amp; Tagged Template Literals
&lt;/h3&gt;

&lt;p&gt;Template literals are great for HTML because you can add newlines and very cleanly have dynamic classes and other attributes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myHTMLTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;
  &amp;lt;!DOCTYPE html&amp;gt;
  &amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;
    &amp;lt;body class="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;"&amp;gt;
      ...
&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use Visual Studio Code the &lt;a href="https://marketplace.visualstudio.com/items?itemName=bierner.lit-html"&gt;Lit-HTML extension&lt;/a&gt; will add syntax highlighting and HTML intellisense features and &lt;a href="https://code.visualstudio.com/docs/editor/emmet"&gt;emmet&lt;/a&gt; shortcuts for templates tagged with a tag called html . The html tag doesn’t have to be the one from the lit-html library even using String.raw will give you the really nice features of HTML inside a JavaScript or TypeScript file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fYf3ZsMB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AYLFHrT-DNqURE-6xg-sjYw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fYf3ZsMB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AYLFHrT-DNqURE-6xg-sjYw.png" alt="HTML syntax highlighting in a JS file"&gt;&lt;/a&gt;&lt;em&gt;HTML syntax highlighting in a JS file&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sanitising HTML with a Tagged Template Literal
&lt;/h3&gt;

&lt;p&gt;When you are outputting HTML that may contain user generated content you have to be careful about malicious JavaScript users may try into inject into all kinds of elements, these kinds of attacks are known as cross-site scripting aka XSS.&lt;/p&gt;

&lt;p&gt;It’s best to strip out dangerous elements and attributes. You can do that in a template literal tag using a library like &lt;a href="https://www.npmjs.com/package/htmlparser2"&gt;html-parser2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We want to have two types of input into the placeholder, raw text strings which needs sanitising and safe HTML which is either authored by us or has been put through the sanitiser. This class just stores a string and we can use it to mark strings that are safe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;SafeHTML&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inStr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPrimitive&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we have our template literal tag function, this does nothing to SafeHTML objects and sanitises raw strings returning a new SafeHTML from our template literal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stringArray&lt;/span&gt;&lt;span class="p"&gt;,...&lt;/span&gt;&lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sanitisedHTMLArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;SafeHTML&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stripHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stringArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;sanitisedHTMLArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SafeHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To strip the HTML first I listed all the elements I wanted to allow and the attributes which are safe, these are mostly all used for formatting or semantics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedTagAttributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;href&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;img&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="na"&gt;abbr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="na"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;li&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;h5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;h6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;hr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;figcaption&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;u&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;ruby&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;small&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;span&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;del&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;td&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
 &lt;span class="na"&gt;ol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedTags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allowedTagAttributes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we use htmlparser2 to go through the input text string and rebuild the HTML string using just the allowed elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;stripHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textOut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;htmlparser2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;

   &lt;span class="nx"&gt;onopentag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tagname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attribs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allowedTags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tagname&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;allowedAttribs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allowedTagAttributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tagname&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tagname&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;attribs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sanitiseURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attribs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;

     &lt;span class="nx"&gt;textOut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tagname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
       &lt;span class="nx"&gt;allowedAttribs&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;attribs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;attribs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
     &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;

   &lt;span class="nx"&gt;ontext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;textOut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;

   &lt;span class="nx"&gt;onclosetag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tagname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allowedTags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tagname&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;textOut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tagname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;decodeEntities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;);&lt;/span&gt;

 &lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inStr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;textOut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we use the html tag function we just created we can now seperate our authored HTML from users unsafe HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsafe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;img onmouseenter="location.href='[https://example.com'](https://example.com')" src="[http://placekitten.com/200/300](http://placekitten.com/200/300)" /&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;safeHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="err"&gt;

&amp;lt;style&amp;gt;
div {
  color: red;
}
&amp;lt;/style&amp;gt;

&amp;lt;div&amp;gt;User Content: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;unsafe&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;.&amp;lt;/div&amp;gt;

&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using template literals with JS frameworks
&lt;/h3&gt;

&lt;p&gt;If you need more functionality than basic templating there are some really light and fast frameworks which use template literals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lit-html&lt;/strong&gt; is pretty well known and designed to work with the polymer web component framework.&lt;br&gt;
&lt;a href="https://github.com/Polymer/lit-html"&gt;&lt;strong&gt;Polymer/lit-html&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Efficient, Expressive, Extensible HTML templates in JavaScript Full documentation is available at…&lt;/em&gt; github.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lighter-html&lt;/strong&gt; is designed to be really fast and very small. It’s really well featured and a great way to build a really fast web site.&lt;br&gt;
&lt;a href="https://github.com/WebReflection/lighterhtml"&gt;&lt;strong&gt;WebReflection/lighterhtml&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Social Media Photo by Kristine Weilert on Unsplash The hyperHTML strength &amp;amp; experience without its complexity 🎉 I am…&lt;/em&gt; github.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By Ada Rose Cannon on October 6, 2020.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/samsung-internet-dev/html-and-templates-javascript-template-literals-2d7494ea3e6"&gt;Canonical link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
  </channel>
</rss>
