<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ivan Lyagushkin</title>
    <description>The latest articles on DEV Community by Ivan Lyagushkin (@javar).</description>
    <link>https://dev.to/javar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F842976%2Faf13a802-2529-4241-9855-5f9c3bd7b86f.jpeg</url>
      <title>DEV Community: Ivan Lyagushkin</title>
      <link>https://dev.to/javar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/javar"/>
    <language>en</language>
    <item>
      <title>External SVGs that you can style</title>
      <dc:creator>Ivan Lyagushkin</dc:creator>
      <pubDate>Mon, 11 Apr 2022 08:11:12 +0000</pubDate>
      <link>https://dev.to/javar/external-svgs-that-you-can-style-2a37</link>
      <guid>https://dev.to/javar/external-svgs-that-you-can-style-2a37</guid>
      <description>&lt;p&gt;You can inline SVGs, use a symbol sprite, make it an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, an &lt;code&gt;&amp;lt;object&amp;gt;&lt;/code&gt; even an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; tag, you can use data URI, css backgrounds, filters and many more &lt;a href="https://cloudfour.com/thinks/svg-icon-stress-test/"&gt;techniques&lt;/a&gt; just to show it to a user. But if you want to utilize all this fancy power of SVGs, you have to inline. Had to. Until now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fancy power of SVGs
&lt;/h2&gt;

&lt;p&gt;What i mean here is a possibility to manipulate SVG's styles from css. It is a must-have feature, especially for icons. You want to change the icon's fill on hover and you don't want to use a separate image for this.&lt;/p&gt;

&lt;p&gt;To achieve this you either inline SVGs directly to your HTML, or you can use a separate file, a symbol sprite, that is also needs to be inserted to the DOM. No other technique allows you to do this. So let's look at inlining and sprites closer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inlining
&lt;/h2&gt;

&lt;p&gt;Inlining is the simplest and the most powerful way of using SVGs. You just place an SVG right to the HTML markup and it works.&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;span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 16 16"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- svg content --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then &lt;a href="https://css-tricks.com/svg-properties-and-css/"&gt;style it with css&lt;/a&gt;, change almost any property, even position and &lt;a href="https://blog.logrocket.com/animating-svg-with-css-83e8e27d739c/"&gt;animate specific parts&lt;/a&gt; of it. But there is an obvious cons of doing so:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the SVG is big, it takes additional time for the whole page to load.&lt;/li&gt;
&lt;li&gt;When using in React with (great) tools like &lt;a href="https://react-svgr.com/"&gt;SVGR&lt;/a&gt;, it increases the javascript bundle size.&lt;/li&gt;
&lt;li&gt;You can't actually control the loading process, like with basic images for example.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Sprite
&lt;/h2&gt;

&lt;p&gt;Another technique that allows to manipulate SVG from css is a sprite of &lt;code&gt;&amp;lt;symbols&amp;gt;&lt;/code&gt;. Content of SVGs is stored in the separate hidden file, and with &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; tag you can reference the right symbol from where you want your image to appear.&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="c"&gt;&amp;lt;!-- hidden sprite on the top of the page --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display:none"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;symbol&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"0 0 16 16"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"16"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- svg content --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/symbol&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- usage --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&amp;gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#icon"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sprite may also be stored in the external file, if you don't care about IE11:&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;svg&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.net/sprite.svg#example"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately you can't set reference to separate SVG-file  in &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt;, you only need a sprite, so this &lt;strong&gt;won't work&lt;/strong&gt;:&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;svg&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.net/icon.svg"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fancy css-manipulation here works, but is limited. You don't have an access through the Shadow boundary, that &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; represents.&lt;/p&gt;

&lt;p&gt;The good news is that cascading is working, so you can change the fill of your SVGs and use &lt;code&gt;currentColor&lt;/code&gt; inside any property. It's just enough for the most of icons-related cases:&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="c"&gt;&amp;lt;!-- sprite --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display:none"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;symbol&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"currentColor"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/symbol&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- icon with class name --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;use&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#icon"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- css --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.icon&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rebeccapurple&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bad thing about sprites is that they are not extendable. You'll end up generating huge files that you have to load on every page and you don't need 99% of it's content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compromise
&lt;/h2&gt;

&lt;p&gt;We obviously need a compromise here, a way to load only necessary SVGs, don't bother our javascript with rendering it and keep the possibility of css-styling.&lt;/p&gt;

&lt;p&gt;And there is such, we can fetch! We need a tool that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetches SVGs in browser. And caches them.&lt;/li&gt;
&lt;li&gt;Puts them into sprite.&lt;/li&gt;
&lt;li&gt;Provides an API to pass reference to this SVG to &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; tag.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first one to think about this was &lt;a href="https://css-tricks.com/ajaxing-svg-sprite/"&gt;Chris Coyier&lt;/a&gt; in 2015. But no one still have written a tool for this. So we did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handy SVG
&lt;/h2&gt;

&lt;p&gt;It is called &lt;strong&gt;Handy SVG&lt;/strong&gt; and it lives on &lt;a href="https://github.com/ivliag/handy-svg"&gt;github&lt;/a&gt; and publishes to npm. So you can:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i handy-svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then in your React code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;HandySvg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handy-svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;iconSrc&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./icon.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HandySvg&lt;/span&gt;
        &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;iconSrc&lt;/span&gt;&lt;span class="p"&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;32&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;32&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you don't use React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handy-svg/lib/injector&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;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn-server.net/icon.svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Fetches svg content and puts it to sprite&lt;/span&gt;
&lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Gets the id of your svg in sprite&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Then you can use it at your will&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;svg&amp;gt;&amp;lt;use href="#&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" /&amp;gt;&amp;lt;/svg&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course it's a compromise, there are some limits, a bit of a FONI  (Flash of No Icons) for example. But still, from all the possibilities that we have, this is the most handy way to use SVG on the web right now.&lt;/p&gt;




&lt;p&gt;The PR's are very welcome and I will be happy to hear any feedback.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>svg</category>
      <category>css</category>
    </item>
    <item>
      <title>Your whole app inside iframe. And it works.</title>
      <dc:creator>Ivan Lyagushkin</dc:creator>
      <pubDate>Wed, 06 Apr 2022 19:16:57 +0000</pubDate>
      <link>https://dev.to/javar/wrap-them-all-odo</link>
      <guid>https://dev.to/javar/wrap-them-all-odo</guid>
      <description>&lt;p&gt;Imagine a big web-service with hundreds of thousands users, complex interfaces and navigation, authorization, and payment integrated. Imagine one day your PO comes to you and asks to make not one part of it, but everything, and embeddable. Is it even possible and how much will it cost?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;Yeah, that question comes to your mind first. Why does someone want to do things like this? The answer is simple - this is the cheapest possible way of integration. If you want as much people as possible to use your widget on their web-pages, you have to embed. In this case the consumer only needs to insert some html tags, or call some javascript - and thats's it, job's done. No development needed.&lt;/p&gt;

&lt;p&gt;It starts making even more sense when your business is connected with sales on the web. If you want to sell airplane tickets or hotel bookings, you have to be on the travel-bloggers web pages. If you want to sell tools for web-advertising, you need to be on the sites like Tilda and Shopify, where people manage their business. And the easiest way to get there is through a embeddable widget.&lt;/p&gt;

&lt;p&gt;Big guys have a &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fb2b.anywayanyday.com%2Fen%2Fb2b%2Fweb%2F" rel="noopener noreferrer"&gt;separate&lt;/a&gt; &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fwww.booking.com%2Faffiliate-program%2Fv2%2Fselfmanaged.en-gb.html" rel="noopener noreferrer"&gt;applications&lt;/a&gt; to work inside a widgets, but what if your business is not that big and you don't have a team of developers to implement every feature twice, for the main service and for the embedded one. In that case this crazy idea comes to your mind. Why do not just embed everything?&lt;/p&gt;

&lt;h2&gt;
  
  
  How?
&lt;/h2&gt;

&lt;p&gt;First, you need to build a proof-of-concept application. For that, let's first create a service, that will act like external consumer of your widget, I'll call it Dummy. You will use it for development, testing, and experimenting. Here are the requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Dummy-service and widget &lt;strong&gt;must&lt;/strong&gt; use different origins. The port address is also a part of the origin, so for the local development you may just run your widget and dummy service on the different ports.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It should be easy to switch the address of your widget-application via the dummy-service interface.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dummy-service must be mobile-friendly, especially if your widgets are.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It will be helpful if dummy-service will mimic to the real-world services that you want to use your widgets on.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I consider Dummy to look like this:&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%2Feaz5z797w2ryo4xo1yda.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%2Feaz5z797w2ryo4xo1yda.png" alt="Separate service for developing and testing embed widget"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From now on, we can start experimenting. Let's create &lt;code&gt;iframe&lt;/code&gt;, set its &lt;code&gt;src&lt;/code&gt; to our application url, reset some styles and insert it to our Dummy.&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;iframe&lt;/span&gt;
    &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"My application widget"&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://my-application.com"&lt;/span&gt;
    &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width:100%; border:none; min-height:300px;"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The first thing you’ll notice — frame filled all available width, but has a hight of only &lt;code&gt;300px&lt;/code&gt; and a vertical scroll bar. Our host application, Dummy in this case, knows nothing about your frame content and can not resize itself to frame’s height.&lt;/p&gt;

&lt;p&gt;The only way for Dummy to respect widget’s application height is through frame communication, and the only way to organize cross-origin frame communication is through &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage" rel="noopener noreferrer"&gt;window.postMessage&lt;/a&gt; API.&lt;/p&gt;

&lt;p&gt;From here it becomes clear, that we need some javascript on the page of Dummy service to listen to all this messages and resize the frame. So, our application will be distributed not just by inserting an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; tag, but with &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag and initialization call.&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%2Fllen8lamnww0aadkfymc.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%2Fllen8lamnww0aadkfymc.png" alt="Initialization section subheader"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialization
&lt;/h2&gt;

&lt;p&gt;The main goal of this script is to provide a javascript API for our consumers to embed our widget. Let’s imagine how may look a call to this API in browser.&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;async&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://some-cdn-server.net/widget/v1/script.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;script&amp;gt;&lt;/span&gt;
   &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;framedWidgetCallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;widget&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;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FramedWidget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
         &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&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="s1"&gt;#container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="na"&gt;consumerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dummy&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Here are the important things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use versioning for initialization script: &lt;code&gt;/widget/v1/script.js&lt;/code&gt;. In the future we may want to  break the backward compatibility to be able to change our widget in any possible way.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My advice is &lt;strong&gt;not to cache&lt;/strong&gt; this script for a long time, especially on the early stages of development. You may want to provide a new functionality with the same script file. Or, the worst scenario, you may find a bug inside this code and you'll want all of you consumers to get it fixed. So don't set &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FHTTP%2FHeaders%2FCache-Control%23cache_directives" rel="noopener noreferrer"&gt;&lt;code&gt;max-age&lt;/code&gt;&lt;/a&gt; to more than couple of hours and just use &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FHTTP%2FHeaders%2FETag" rel="noopener noreferrer"&gt;&lt;code&gt;ETag&lt;/code&gt;&lt;/a&gt; for cache invalidation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;async&lt;/code&gt; attribute with your script tag, or be ready, that the consumer will set it. To be sure that  your script is loaded when you call an initialization function, use the callback as shown in the code above, or fire some custom event.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Provide every consumer with unique id, it will be used for security, metrics tracking, and problems investigations.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The script itself may be written in OOP style, I prefer using typescript when possible, but you may choose anything that works for you:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Window&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;FramedWidget&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;FramedWidget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;framedWidgetCallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;InitParams&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;consumerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;height-changed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FramedWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InitParams&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="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;frameOrigin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://my-application.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLIFrameElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;parseMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&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;result&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="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;e&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;postMessageHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&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;frameOrigin&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;height-changed&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;frame&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&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;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&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;private&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InitParams&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;frame&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;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;iframe&lt;/span&gt;&lt;span class="dl"&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;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&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;frameOrigin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?consumerId=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consumerId&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frame&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;style&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="s1"&gt;width:100%; border:none; min-height:300px;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&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;frame&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nb"&gt;window&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;message&lt;/span&gt;&lt;span class="dl"&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;postMessageHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;destroy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&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;postMessageHandler&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FramedWidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;FramedWidget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;framedWidgetCallback&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 things to notice are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Provide your consumers with &lt;code&gt;destroy&lt;/code&gt; method out of the box, they should be able to use your code inside single-page applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When parsing messages inside &lt;code&gt;postMessageHandler&lt;/code&gt; always check the &lt;code&gt;event.origin&lt;/code&gt; and wrap your &lt;code&gt;JSON.parse&lt;/code&gt; code inside &lt;code&gt;try ... catch&lt;/code&gt; blocks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set &lt;code&gt;min-height&lt;/code&gt; style attribute to the frame to some meaningful value. It will help on initial rendering and in case if something goes not as planned.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build this code to be used in as many browsers as possible. The fallback with message for older browser must be a part of your widget code, not a part of this script. My advice is to set &lt;code&gt;"target": "es6"&lt;/code&gt; in your &lt;code&gt;tsconfig.json&lt;/code&gt; or something like &lt;code&gt;&amp;gt; 0.2%, not dead&lt;/code&gt; in .browserslistrc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You may also want to use &lt;code&gt;debounce&lt;/code&gt; when changing the frame hight to provide better performance.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I should also mention that there are some libraries to resize frames to fit their contained content, the most popular is &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fgithub.com%2Fdavidjbradshaw%2Fiframe-resizer%2Fblob%2Fmaster%2Fsrc%2FiframeResizer.js" rel="noopener noreferrer"&gt;iframe-resizer&lt;/a&gt;, but maybe you don't need all of it's complexity.&lt;/p&gt;

&lt;p&gt;So far so good. Now we can initialize our widget through script and it will be resized horizontally and vertically. Everything seems to work fine, until we click our first external link, for example, to social media. Yep, the Facebook will be opened inside the frame. Navigation inside the frame might be a really tricky, but now we have all the tools to make it work right.&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%2F180nwk3ywtsk1pb6azhe.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%2F180nwk3ywtsk1pb6azhe.png" alt="Navigation section subheader"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigation
&lt;/h2&gt;

&lt;p&gt;There are only four types of navigation cases you may want to differ inside your widget:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Real links that should be opened &lt;em&gt;inside the frame&lt;/em&gt;. This is a simple case, just use &lt;code&gt;target="self"&lt;/code&gt; and everything will be fine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real links that should be opened in the &lt;em&gt;host window&lt;/em&gt;. Also easy to solve, &lt;code&gt;target="top"&lt;/code&gt; will do the trick.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transitions made through javascript, &lt;code&gt;window.location.href&lt;/code&gt; or &lt;code&gt;history.pushState&lt;/code&gt;, that you want to do &lt;em&gt;inside the frame&lt;/em&gt; - just leave them as they are, they are supposed to work fine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Transitions made through javascript, that you want to do in the &lt;em&gt;host window&lt;/em&gt;. The only way to do it is through the &lt;code&gt;window.parent.postMessage&lt;/code&gt; calls.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For everything here to work properly on every  page of your  application you need to know  either it is running inside the frame or standalone. The way of receiving this information in browser is &lt;a href="https://medium.com/r/?url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FAPI%2FWindow%2Fparent" rel="noopener noreferrer"&gt;quite simple&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isInFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;So, if your application runs only in browser, that is actually all you need.&lt;/p&gt;

&lt;p&gt;But the server-side logic is much trickier. There is no way to figure out where the application is running by looking at the HTTP-request, no special headers, nothing more. So, you need to use custom urls when your application runs inside the frame. Here are the possibilities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use query param, like &lt;code&gt;?inFrame=1&lt;/code&gt; and append it to all the links of your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use custom subdomain for framed application, like &lt;code&gt;framed.my-application.com&lt;/code&gt;. This is a ‘cleaner’ way, because your links and application logic might not change that much. The caveat here is that if you want your authorization and other cookie-based logic to work on this subdomain pages, you need to always &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#define_where_cookies_are_sent" rel="noopener noreferrer"&gt;specify domain&lt;/a&gt; when setting your cookies.&lt;br&gt;
Another important restriction here is that data stored in &lt;strong&gt;local/session storage won’t be available on subdomains&lt;/strong&gt;, so bear this in mind and choose wisely.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When this is achieved, you may customize some of your application behavior, when it runs inside the frame. For example, you may want to hide your header or footer, change some contact information for your support to know that they are dealing with widget users, and so on.&lt;/p&gt;

&lt;p&gt;So, application works fine inside and outside the frame, it resizes properly, you may follow any link. Even authorization works just as expected, server receives cookies from your embedded widget, the job’s seams to be done. Until you open your widget with Safari browser.&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%2F4kyw7s3lfvjsqnshbptt.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%2F4kyw7s3lfvjsqnshbptt.png" alt="Authorization section header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization
&lt;/h2&gt;

&lt;p&gt;The reason authorization won’t work in Safari is the &lt;a href="https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/" rel="noopener noreferrer"&gt;Full Third-Party Cookie Blocking&lt;/a&gt; policy. Safari won’t send any cookies for cross-site resources, that means that your widget just won’t get any cookies in the Safari. And not just in the Safari, but in all of the &lt;a href="https://en.wikipedia.org/wiki/WebKit" rel="noopener noreferrer"&gt;WebKit-based&lt;/a&gt; browsers.&lt;/p&gt;

&lt;p&gt;And trust me here, I tried a lot of very different approaches, the only way to do it right is by using &lt;a href="https://webkit.org/blog/8124/introducing-storage-access-api/" rel="noopener noreferrer"&gt;Storage Access API&lt;/a&gt; introduced by the WebKit developers. What you need here is to &lt;em&gt;ask&lt;/em&gt; users for the access to the data, stored in their browsers. The restriction is that you can do it only after user interaction, like click event.&lt;/p&gt;

&lt;p&gt;I consider doing it this way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When application is loaded and the user is not authorized, firstly check the &lt;code&gt;document.hasStorageAccess()&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If this resolves as &lt;code&gt;false&lt;/code&gt;, you should show the user a page with an explanation of what is the storage access and why you ask for it, and of course the button to grant it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After the storage access is granted, you may proceed to the authorization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The access to storage will be granted for the origin and &lt;code&gt;document.hasStorageAccess()&lt;/code&gt; will resolve to true afterwards. The duration of this access vary from browser to browser and may be changed because all the Storage Access API is still a &lt;a href="https://privacycg.github.io/storage-access/" rel="noopener noreferrer"&gt;draft&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code for this flow may look like this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkStorageAccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasStorageAccess&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;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasStorageAccess&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestStorageAccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasStorageAccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkStorageAccess&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;hasStorageAccess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;proceedToAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&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;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestStorageAccess&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;proceedToAuthorization&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;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;proceedToErrorPage&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="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="s1"&gt;.grant-access-button&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="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;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestStorageAccess&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You may now use authorization in your widget. The only important thing left is security.&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%2Fcwqgpzuiogem4ycwfxyj.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%2Fcwqgpzuiogem4ycwfxyj.png" alt="Security section header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;From the security perspective, you want to control the pages that embed your widget. This is achievable with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors" rel="noopener noreferrer"&gt;&lt;code&gt;frame-ancestors&lt;/code&gt;&lt;/a&gt; directive inside your &lt;code&gt;Content-Security-Policy&lt;/code&gt; HTTP-header. Here is my advice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Use some sort of identifier for your consumer, like &lt;code&gt;consumerId&lt;/code&gt; mentioned above, and set the &lt;code&gt;frame-ancestors&lt;/code&gt; to only specify domains used by this consumer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;https://&lt;/code&gt; for all the domains listed in &lt;code&gt;frame-ancestors&lt;/code&gt; directive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check the &lt;code&gt;event.origin&lt;/code&gt; when listening to the &lt;code&gt;message&lt;/code&gt; event.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use only &lt;code&gt;Secure&lt;/code&gt; and &lt;code&gt;HttpOnly&lt;/code&gt; cookies to store authorization data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I would not recommend to set &lt;code&gt;sandbox&lt;/code&gt; attribute to your iframe with any value.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;And that’s it. With all these preparations, you can build a truly responsible, secure and feature-full widget made on top of your base application, without the need to rewrite all of it and to maintain a separate versions of it.&lt;/p&gt;

&lt;p&gt;Just make the testing of a widget a part of your e2e-pipeline and remember to check it when developing new features.&lt;/p&gt;

&lt;p&gt;If you have any further questions or want to discuss the topic — please contact me here.&lt;/p&gt;

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