<?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: Alex Inkin</title>
    <description>The latest articles on DEV Community by Alex Inkin (@waterplea).</description>
    <link>https://dev.to/waterplea</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%2F442490%2F440f898d-bfb2-4d96-9492-45ca5ccc6416.jpg</url>
      <title>DEV Community: Alex Inkin</title>
      <link>https://dev.to/waterplea</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/waterplea"/>
    <language>en</language>
    <item>
      <title>Maskito: a Holy Grail of input masking</title>
      <dc:creator>Alex Inkin</dc:creator>
      <pubDate>Sun, 02 Jul 2023 12:10:29 +0000</pubDate>
      <link>https://dev.to/waterplea/maskito-a-holy-grail-of-input-masking-3gn4</link>
      <guid>https://dev.to/waterplea/maskito-a-holy-grail-of-input-masking-3gn4</guid>
      <description>&lt;p&gt;If you have ever worked on complex user forms, you definitely needed a masking solution. You want your numbers to be properly formatted so it is easy for users to make sure they have entered the correct amount at a glance. Or compare credit card number with an actual card, enter their phone or birthday or an appointment time. Masking has a lot of use cases on the web but to find a good solution is not an easy task. A lot of the time masking libraries can cause frustration for both developers and users. Common issues are jumping caret, troubles with added symbols like dashes or brackets, browser autofill or errors in server side rendering and convoluted API.&lt;/p&gt;

&lt;p&gt;We were no strangers to these troubles and at some point we decided to dedicate serious resources to our own solution. Today I would like to present it to you and explain why it is worth your attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Maskito and why should you care?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Tinkoff/maskito" rel="noopener noreferrer"&gt;Maskito&lt;/a&gt; is a set of libraries for input masking with focus on both UX and DX. You can check out our &lt;a href="https://tinkoff.github.io/maskito" rel="noopener noreferrer"&gt;extensive documentation portal&lt;/a&gt;. There you can find plenty of examples, as well as a detailed walkthrough of the API. The “Getting started” section will explain the basics and will quickly get you familiar with concepts and use cases. You can also read a &lt;a href="https://medium.com/its-tinkoff/maskito-is-a-new-collection-of-libraries-for-text-field-masking-f64ec71951df" rel="noopener noreferrer"&gt;more technical article&lt;/a&gt; by Maskito lead developer &lt;a href="https://twitter.com/nsbarsukov" rel="noopener noreferrer"&gt;Nikita Barsukov&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Of course, Maskito is not the only solution you can find. But I believe there are certain things setting it apart from most alternatives available right now. Hence the ambitious title of this article. Let’s briefly explore why you should consider Maskito if you are looking for a masking solution for your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backed by enterprise
&lt;/h3&gt;

&lt;p&gt;Unlike many open source libraries that are maintained by individuals, Maskito is a product developed and used by one of the world’s leading fintech companies. We are seasoned open source authors getting paid for what we do so you can rely on timely support and continuous development.&lt;/p&gt;

&lt;p&gt;Our team already has a stock of welcomed projects, especially in the Angular ecosystem, such as &lt;a href="https://github.com/Tinkoff/taiga-ui" rel="noopener noreferrer"&gt;Taiga UI&lt;/a&gt;, &lt;a href="https://github.com/Tinkoff/ng-polymorpheus" rel="noopener noreferrer"&gt;ng-polymorpheus&lt;/a&gt; and &lt;a href="https://github.com/Tinkoff/ng-web-apis" rel="noopener noreferrer"&gt;Web APIs for Angular&lt;/a&gt; to name a few. We take them very seriously because they are not pet projects or hobbies (although we love them as if they were). Therefore you can expect our documentation to be easy to navigate, examples to be plentiful and communication to go effortlessly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Framework agnostic
&lt;/h3&gt;

&lt;p&gt;Whether you use React, Vue or Angular for your product or you rely on some other framework or even vanilla JavaScript — Maskito got you covered. Our main package is dependency free and can be used in any frontend application. And so are mask presets that we will cover below.&lt;/p&gt;

&lt;p&gt;At the time of writing we have dedicated packages to use Maskito in React, Vue and Angular with comfort. Since the public API is rather succinct, it would be easy to expand support to other popular frameworks. Actual masking configuration is the same and can be shared across different projects and architectures with ease.&lt;/p&gt;

&lt;h3&gt;
  
  
  Environment agnostic
&lt;/h3&gt;

&lt;p&gt;Maskito works in all modern browsers regardless of the environment you run it in. You can be using Web Components with Shadow DOM or employ SSR to improve your time to interactive and SEO — your inputs will not give you trouble by trying to access ‘window’ under nodejs or messing with encapsulated focus. It will also work properly on touch devices and virtual keyboards on both inputs and textarea elements. Clipboard interaction, undo/redo, text drag and drop or browser autofill are also covered by Maskito.&lt;/p&gt;

&lt;p&gt;Our goal is to create a go-to masking solution for the web and the web is as diverse as it gets. If you face any issues with some specific configuration, please do not hesitate to &lt;a href="https://github.com/Tinkoff/maskito/issues/new/choose" rel="noopener noreferrer"&gt;raise an issue&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quality code
&lt;/h3&gt;

&lt;p&gt;Maskito is maintained by an experienced lead developer and a team of contributors with a history of delivering widely used versatile solutions and open source libraries. Multiple Google Developer Experts curate the project and make sure architectural decisions are well thought through and make sense in the long run.&lt;/p&gt;

&lt;p&gt;All code is written in strict TypeScript and covered by tons of e2e tests and community contributions are thoroughly reviewed. We have tightly configured linters and automated pipelines we perfected for years on other projects to make sure technical flaws do not make it to the release. We use it in a multi million users business product. It is in our best interest that the caret does not jump all over your input fields.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not just us
&lt;/h3&gt;

&lt;p&gt;While we of course trust our solution and are happy with it, you might be wondering if it would suit your particular needs. We have a wide array of products with different browser and device usage, different specs and requirements. Our team consists of engineers that specialize in generalized solutions and flexible APIs. So we know there’s an endless pool of use cases and we are prepared.&lt;/p&gt;

&lt;p&gt;But it is not just us — &lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic Framework&lt;/a&gt;, a multi platform UI solution with nearly 50k stars on GitHub has adopted Maskito as its official masking &lt;a href="https://ionic.io/blog/announcing-ionic-v7-1" rel="noopener noreferrer"&gt;library recommendation&lt;/a&gt;. Their team did an investigation of existing alternatives and considered an option to develop their own mask. They decided Maskito would satisfy the needs of their extremely varied user base and added examples of masking their components to the &lt;a href="https://ionicframework.com/docs/api/input#input-masking" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ready to use
&lt;/h3&gt;

&lt;p&gt;Maskito comes with a dedicated package of ready-to-use masks. We maintain a huge components library that has number formatting, credit cards, phones, dates etc. It is used in dozens of applications across our ecosystem, where additional masking is required for zip codes, IP addresses, serial numbers and so on. Once they are implemented and properly tested, all generally applicable cases are extracted and reused.&lt;/p&gt;

&lt;p&gt;This is an ever growing collection of presets that you can take as-is and be sure they behave properly. You can contribute to it or raise a feature request for a particular solution at our &lt;a href="https://github.com/Tinkoff/maskito" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;. This makes Maskito as tiny or as comprehensive as you need it to be. Core package is only about 3KB gzip and every piece of presets is tree shakable so your bundle is in safe hands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Maskito is free for both personal and commercial use and is released under Apache 2.0 license. I am really proud of what the team is doing and believe it to be the best solution for the task. I hope it can help you bring your ideas to life in a smooth way both for your users and developers. Check Maskito out and if you like it, support us with a star and help us spread the word. Happy masking everyone!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Taiga UI: A year in Open Source</title>
      <dc:creator>Alex Inkin</dc:creator>
      <pubDate>Fri, 24 Dec 2021 13:28:19 +0000</pubDate>
      <link>https://dev.to/angular/taiga-ui-a-year-in-open-source-416l</link>
      <guid>https://dev.to/angular/taiga-ui-a-year-in-open-source-416l</guid>
      <description>&lt;p&gt;&lt;a href="https://taiga-ui.dev" rel="noopener noreferrer"&gt;Taiga UI&lt;/a&gt; is a huge Angular components library. We at &lt;a href="https://www.tinkoff.ru/eng" rel="noopener noreferrer"&gt;Tinkoff&lt;/a&gt; were developing it closed-source for a couple of years before finally going public with a second major version. It’s been a year since our open source release and today I want to look back at this part of our journey and lay down some plans for 2022. Let’s go!&lt;/p&gt;

&lt;h1&gt;
  
  
  Open source
&lt;/h1&gt;

&lt;p&gt;Over this time the community started to build up. One benefit for going &lt;a href="https://github.com/TinkoffCreditSystems/taiga-ui" rel="noopener noreferrer"&gt;open source on GitHub&lt;/a&gt; is contribution made simpler even for colleagues from different projects. The environment is familiar, no extra authentication or VPN required and the pipeline is clear. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F54ae293y2mv6yqvz1671.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F54ae293y2mv6yqvz1671.png" alt=" " width="512" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also spent quite some time to improve our processes utilizing many different tools to help us ship new versions safer and faster. &lt;/p&gt;

&lt;p&gt;Taiga UI is a monorepo that includes several libraries and a demo application that we deploy using GitHub Pages. Now it is managed by &lt;a href="https://nx.dev/" rel="noopener noreferrer"&gt;NX tools&lt;/a&gt; that provide a lot of useful commands and increase speed of building and testing at both local development and CI/CD pipelines. If you plan on working with monorepos you should definitely try NX!&lt;/p&gt;

&lt;p&gt;Whenever a Pull Request is created we need to be able to quickly checkout the changes. Reading code diff is great, but sometimes you just need to tinker with the new version, test it on mobile, different browsers and OS. Cloud services are perfect for this case, they allow you to deploy the code temporarily and access it with a link from any device. We chose &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt; to host it for us and a Github action posts a link to the deployment as a comment in the Pull Request. It works like a charm and speeds up code reviews a lot. Read &lt;a href="https://firebase.google.com/docs/hosting/github-integration" rel="noopener noreferrer"&gt;this article&lt;/a&gt; to set it up on your repository!&lt;/p&gt;

&lt;p&gt;Moreover, every PR runs a set of &lt;a href="https://www.cypress.io/" rel="noopener noreferrer"&gt;Cypress&lt;/a&gt; screenshot tests that iterates over the demo portal and compares current components with their reference from the main branch. Cypress has a commercial solution where you can easily access failed screenshots through a dashboard. But we created a little &lt;a href="https://github.com/TinkoffCreditSystems/argus" rel="noopener noreferrer"&gt;Github bot&lt;/a&gt; that stores failed screenshots in a temporary branch and posts them to the PR as a comment, updating it on every push. This makes identifying problems with the UI library fast and easy. We opensourced this bot so you can use it too, read &lt;a href="https://medium.com/its-tinkoff/bots-should-work-developers-should-think-writing-github-app-with-node-js-2e8eb049d7e4" rel="noopener noreferrer"&gt;this article&lt;/a&gt; going over it in detail!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fdelq3c2gp2joqbe69yaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdelq3c2gp2joqbe69yaj.png" alt=" " width="512" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s also a &lt;a href="https://github.com/typicode/husky" rel="noopener noreferrer"&gt;husky&lt;/a&gt; precommit hook with &lt;a href="https://github.com/eslint/eslint" rel="noopener noreferrer"&gt;ESlint&lt;/a&gt; and &lt;a href="https://github.com/prettier/prettier" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt; fixing and formatting changed code on every commit with &lt;a href="https://github.com/okonet/lint-staged" rel="noopener noreferrer"&gt;lint-staged&lt;/a&gt; which makes sure malformed code doesn't even make it to the Pull Request. Combined with &lt;a href="https://github.com/conventional-changelog/standard-version" rel="noopener noreferrer"&gt;standard-version&lt;/a&gt; and strict commit messages it makes releasing and changelog generation a breeze. For a contributor the workflow is as smooth as:&lt;/p&gt;

&lt;p&gt;fork → npm ci → npm start → code → commit → push&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s new?
&lt;/h1&gt;

&lt;p&gt;When 2.0 went public it already was pretty big. But over the course of 2021 we added and improved a lot of things. With ideas and help from the community we significantly expanded customization and localization capabilities. This would be very helpful for our own international projects too. Taiga UI today has over 10 languages for built-in texts, RTL support for most of the components and various formats for money and dates. We also provide “ng add” schematic to get you started smoothly with Taiga UI. Let’s look at the most notable additions to our 150+ components base this year!&lt;/p&gt;

&lt;h2&gt;
  
  
  New components
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://taiga-ui.dev/components/sheet" rel="noopener noreferrer"&gt;Sheet&lt;/a&gt;&lt;/strong&gt; — mobile sliding dialog&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fpmrmtd9tqoyi7j1qgtnp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fpmrmtd9tqoyi7j1qgtnp.png" alt=" " width="333" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://taiga-ui.dev/components/tree" rel="noopener noreferrer"&gt;Tree&lt;/a&gt;&lt;/strong&gt; — a flexible component to display tree-like data structures&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fhmdc5346q5tefw14kiif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fhmdc5346q5tefw14kiif.png" alt=" " width="496" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://taiga-ui.dev/components/pdf-viewer" rel="noopener noreferrer"&gt;PdfViewer&lt;/a&gt;&lt;/strong&gt; — a custom dialog to preview PDFs in iframe&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fvpnrss9fhyq5bjayazgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fvpnrss9fhyq5bjayazgi.png" alt=" " width="512" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://taiga-ui.dev/components/carousel" rel="noopener noreferrer"&gt;Carousel&lt;/a&gt;&lt;/strong&gt; — a common UI pattern for slider of images&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fw1rmy7sguc6tpi29uiwj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fw1rmy7sguc6tpi29uiwj.png" alt=" " width="512" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://taiga-ui.dev/components/arc-chart" rel="noopener noreferrer"&gt;ArcChart&lt;/a&gt;&lt;/strong&gt; — a new way to display numerical data&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fl2xr0u9vmcpm9ic5j335.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fl2xr0u9vmcpm9ic5j335.png" alt=" " width="512" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  New add-on packages
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://taiga-ui.dev/components/table" rel="noopener noreferrer"&gt;Table&lt;/a&gt;&lt;/strong&gt; — an interactive table component and related utilities&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Frlyh5dfe2wz4jqtd9rp5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Frlyh5dfe2wz4jqtd9rp5.png" alt=" " width="512" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://taiga-ui.dev/components/editor-new" rel="noopener noreferrer"&gt;Editor&lt;/a&gt;&lt;/strong&gt; — a rich text editor based on &lt;a href="https://tiptap.dev/" rel="noopener noreferrer"&gt;tiptap 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fk09jqb9rzbm2bbeldjt7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fk09jqb9rzbm2bbeldjt7.png" alt=" " width="512" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://taiga-ui.dev/components/preview" rel="noopener noreferrer"&gt;Preview&lt;/a&gt;&lt;/strong&gt; — a custom dialog to preview aribtrary content such as images and documents&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fv0alvb5kmnig0f8nx893.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fv0alvb5kmnig0f8nx893.png" alt=" " width="512" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve also added a bunch of helpful utils, tokens, services and directives, such as Pan, Swipe, DropdownHover and more and a night theme for all components:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fkhkbdzh9ei1jy0h9jy06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fkhkbdzh9ei1jy0h9jy06.png" alt=" " width="512" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s coming?
&lt;/h1&gt;

&lt;p&gt;It was a productive year. We’ve grown a lot in infratructure and content, we started to build community of users, most notably from cryptocurrency area as it seems from the screenshots that come with user questions 🙂 In the coming year we plan to exapand our localization and internationalization options so that developers from across the globe can enjoy Taiga UI and use it in whatever project they are working on. Here’s a brief overview of what we plan to focus on in 2022:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improve and stabilize new Editor add-on package&lt;/li&gt;
&lt;li&gt;Make all native inputs accessible from the outside of Taiga UI controls so it’s easy to assign attributes and listen to native events&lt;/li&gt;
&lt;li&gt;Rework some of our internals to rely more on CSS and less on JavaScript which would reduce change detection cycles&lt;/li&gt;
&lt;li&gt;Utilize DI more for customization&lt;/li&gt;
&lt;li&gt;Drop dependency on global styles&lt;/li&gt;
&lt;li&gt;Create ComponentHarnesses for Taiga UI components so they can be easily tested&lt;/li&gt;
&lt;li&gt;Support different implementations of notifications, like we do now for dialogs&lt;/li&gt;
&lt;li&gt;Reduce tech debt such as old components waiting for refactor and outdated mask library&lt;/li&gt;
&lt;li&gt;Prepare for the next major release with Angular 13 and Ivy distribution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you’re happy with Taiga UI and if you didn’t try it — please give it a shot! Feel free to open &lt;a href="https://github.com/TinkoffCreditSystems/taiga-ui/discussions" rel="noopener noreferrer"&gt;GitHub discussion&lt;/a&gt; or contact us over at &lt;a href="https://discord.gg/zrB2EdJjEy" rel="noopener noreferrer"&gt;Angular Discord&lt;/a&gt;. For Russian speaking users we have a &lt;a href="https://t.me/taiga_ui" rel="noopener noreferrer"&gt;Telegram chat&lt;/a&gt;. Our issues list is open for feature requests and bug reports. And it also always has &lt;a href="https://github.com/TinkoffCreditSystems/taiga-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22contributions+welcome%22" rel="noopener noreferrer"&gt;some things for you to try and solve&lt;/a&gt; if you want to contribute! Merry Christmas and an awesome New Year to you all! 🎄&lt;/p&gt;

</description>
      <category>angular</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Demystifying Taiga UI root component: portals pattern in Angular</title>
      <dc:creator>Alex Inkin</dc:creator>
      <pubDate>Tue, 26 Jan 2021 12:14:59 +0000</pubDate>
      <link>https://dev.to/taiga-ui/demystifying-taiga-ui-root-component-portals-pattern-in-angular-1fal</link>
      <guid>https://dev.to/taiga-ui/demystifying-taiga-ui-root-component-portals-pattern-in-angular-1fal</guid>
      <description>&lt;p&gt;Just before new year, &lt;a href="https://twitter.com/marsibarsi" rel="noopener noreferrer"&gt;Roman&lt;/a&gt;, my colleague, &lt;a href="https://indepth.dev/posts/1413/taiga-ui" rel="noopener noreferrer"&gt;announced&lt;/a&gt; our new Angular UI kit library &lt;a href="https://github.com/TinkoffCreditSystems/taiga-ui" rel="noopener noreferrer"&gt;Taiga UI&lt;/a&gt;. If you go through &lt;a href="https://taiga-ui.dev/getting-started" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt; steps, you will see that you need to wrap your app with the &lt;code&gt;tui-root&lt;/code&gt; component. Let's see what it does and explore what portals are and how and why we use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a portal?
&lt;/h2&gt;

&lt;p&gt;Imagine you have a select component. It has a drop-down block with suggestions. If we keep it at the same position in DOM as the hosting component, we will run into all sorts of trouble. Items pop through and containers can chop off content:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FpDxYWjQAQw9IlXhKaiR9Z8KgaHuFouln4FJbb2W1AipjnJLIgxBBcs9__-nF8iAVD9A1ksueyCHi-bosc7bNO2EaxX_7BQUpPbZs16vemgdPIizFYAgvpUcPGeE5QYuK9Yz8gwaZ" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh3.googleusercontent.com%2FpDxYWjQAQw9IlXhKaiR9Z8KgaHuFouln4FJbb2W1AipjnJLIgxBBcs9__-nF8iAVD9A1ksueyCHi-bosc7bNO2EaxX_7BQUpPbZs16vemgdPIizFYAgvpUcPGeE5QYuK9Yz8gwaZ" width="774" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Verticality issues are often solved with &lt;code&gt;z-index&lt;/code&gt;, effectively starting World War Z in your app. It's not uncommon to see values like 100, 10000, 10001. But even if you manage to get it right — &lt;code&gt;overflow: hidden&lt;/code&gt; would still get you there. So what can we do? Instead of having drop-down near its host we can show it in a dedicated container on top of everything. Then your application content can live in its own &lt;a href="https://developer.mozilla.org/ru/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context" rel="noopener noreferrer"&gt;isolated context&lt;/a&gt; eliminating &lt;code&gt;z-index&lt;/code&gt; problems. This container is exactly what a portal is. And it is what the Taiga UI root component sets up for you, among other things. Let's look at its template:&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;tui-scroll-controls&amp;gt;&amp;lt;/tui-scroll-controls&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;tui-portal-host&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;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;ng-content&amp;gt;&amp;lt;/ng-content&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tui-dialog-host&amp;gt;&amp;lt;/tui-dialog-host&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"tuiOverDialogs"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tui-notifications-host&amp;gt;&amp;lt;/tui-notifications-host&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"tuiOverNotifications"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/tui-portal-host&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"tuiOverPortals"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;tui-hints-host&amp;gt;&amp;lt;/tui-hints-host&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-content&lt;/span&gt; &lt;span class="na"&gt;select=&lt;/span&gt;&lt;span class="s"&gt;"tuiOverHints"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generic and dedicated portals
&lt;/h2&gt;

&lt;p&gt;Both &lt;code&gt;tui-dialog-host&lt;/code&gt; and &lt;code&gt;tui-portal-host&lt;/code&gt; are portals in their nature. But they work differently. Let's explore the second one first. Taiga UI uses it mostly to display drop-downs. But it's a generic container. It is controlled by a very simple service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;@Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="n"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TuiPortalService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TuiPortalHostComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;add&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="n"&gt;componentFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ComponentFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="n"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Injector&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;ComponentRef&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;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="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponentChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;componentFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;({&lt;/span&gt;&lt;span class="n"&gt;hostView&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="n"&gt;ComponentRef&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;hostView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;addTemplate&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="n"&gt;templateRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TemplateRef&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;EmbeddedViewRef&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;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="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addTemplateChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;templateRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;removeTemplate&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;viewRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EmbeddedViewRef&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;viewRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&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;And the component itself is rather straightforward. All it does is show templates and dynamic components on top of everything. No other logic is included (except a little &lt;code&gt;position: fixed&lt;/code&gt; helper for iOS). It means that positioning, closing and the rest is handled by portal items on their own. It's a good idea to have a generic portal for special cases. Like a fixed «Scroll to top» button displayed above content or anything else you, as a library user might need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drop-downs
&lt;/h2&gt;

&lt;p&gt;If we were to architect a drop-down — we would need to come up with a positioning solution. We have several options here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Position drop-down once and prevent scrolling while it's open. This is what material does by default.&lt;/li&gt;
&lt;li&gt; Position once and close if scrolling occurred. That's how native drop-downs behave.&lt;/li&gt;
&lt;li&gt; Follow host position when it changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We went with the third option. It's not that trivial as it turned out. You cannot really get two positions in sync, even with &lt;code&gt;requestAnimationFrame&lt;/code&gt;. Because once you query the host position — it triggers a layout recalculation. So by the time the next frame comes and drop-down is positioned — the host already changes location a little bit. This causes visible jumps, even on fast machines. We got around that by using absolute positioning, rather than fixed. Because the portal container wraps the entire page, position values stay the same during scroll. If the host is in a fixed container, though, it would still jump. But we can detect that when we open the drop-down and use fixed positioning for it as well.&lt;/p&gt;

&lt;p&gt;And then there's this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F6B9coKjAaDvDtM0HzbHiEuP9RXWe17C488dJN94Pfhe7ToKQ_-kj9M9xZYKPvO4tY5NJ7h9gLaQRJfC0AcJ_7SRLHriOsNM_jsBbn6bPgBRQDM-V6v_WLjkSDSEXm8lWJ96Xh4Gi" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh4.googleusercontent.com%2F6B9coKjAaDvDtM0HzbHiEuP9RXWe17C488dJN94Pfhe7ToKQ_-kj9M9xZYKPvO4tY5NJ7h9gLaQRJfC0AcJ_7SRLHriOsNM_jsBbn6bPgBRQDM-V6v_WLjkSDSEXm8lWJ96Xh4Gi" width="600" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the host leaves the visible area — we need to close the drop-down. That's a job for Obscured service. It detects when the host is fully obscured by anything and closes drop-down in that case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dialogs
&lt;/h2&gt;

&lt;p&gt;For dedicated portals study we can take a look at dialogs. Toast notifications and hints are very similar but there are some interesting topics to discuss with modals.&lt;/p&gt;

&lt;p&gt;This is how dialog host looks like:&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;section&lt;/span&gt;
   &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let item of dialogs$ | async"&lt;/span&gt;
   &lt;span class="na"&gt;polymorpheus-outlet&lt;/span&gt;
   &lt;span class="na"&gt;tuiFocusTrap&lt;/span&gt;
   &lt;span class="na"&gt;tuiOverscroll=&lt;/span&gt;&lt;span class="s"&gt;"all"&lt;/span&gt;
   &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"dialog"&lt;/span&gt;
   &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"dialog"&lt;/span&gt;
   &lt;span class="na"&gt;aria-modal=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
   &lt;span class="na"&gt;[attr.aria-labelledby]=&lt;/span&gt;&lt;span class="s"&gt;"item.id"&lt;/span&gt;
   &lt;span class="na"&gt;[content]=&lt;/span&gt;&lt;span class="s"&gt;"item.component"&lt;/span&gt;
   &lt;span class="na"&gt;[context]=&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;
   &lt;span class="err"&gt;[@&lt;/span&gt;&lt;span class="na"&gt;tuiParentAnimation&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;
&lt;span class="nt"&gt;&amp;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;class=&lt;/span&gt;&lt;span class="s"&gt;"overlay"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of being a generic host it has an &lt;code&gt;ngFor&lt;/code&gt; loop over particular items. This allows us to bundle some logic in, like focus trap and page scroll blocking. There is also a clever use of dependency injection here, allowing dialogs to be design and data model agnostic. Host collects observables with dialogs through a dedicated multi token, merges these streams and shows the result. That way you can have multiple designs for dialogs in the same app. Taiga UI has two built-in designs — base and mobile. But you can easily add your own. Let's see how.&lt;/p&gt;

&lt;p&gt;Dialog service returns &lt;code&gt;Observable&lt;/code&gt;. When you subscribe to it, modal popup is shown, when you terminate subscription it is closed. Dialog can also send back data through that stream. First, we design our dialog component. All that's important here, really, is that you can inject &lt;code&gt;POLYMORPHEUS_CONTEXT&lt;/code&gt; in constructor. It would contain an object with &lt;code&gt;content&lt;/code&gt; and &lt;code&gt;observer&lt;/code&gt; for a particular dialog instance. You can close dialog from within by calling &lt;code&gt;complete&lt;/code&gt; on &lt;code&gt;observer&lt;/code&gt; and you can send back data using &lt;code&gt;next&lt;/code&gt; method. Plus all the options you will provide to the service that we will create by extending an abstract class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DIALOG&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PolymorpheusComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyDialogComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MyDialogOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;label&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="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sc"&gt;'s'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;@Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="n"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyDialogService&lt;/span&gt; &lt;span class="n"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AbstractTuiDialogService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyDialogOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DIALOG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;defaultOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_OPTIONS&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;In it we provide default config and a component to use and we're all set.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Dialogs, like everything in Taiga UI use &lt;/em&gt;&lt;a href="https://github.com/TinkoffCreditSystems/ng-polymorpheus" rel="noopener noreferrer"&gt;&lt;em&gt;ng-polymorpheus&lt;/em&gt;&lt;/a&gt;&lt;em&gt; for customizable content. You can read more about making interface free, flexible components with it in &lt;/em&gt;&lt;a href="https://indepth.dev/posts/1314/agnostic-components-in-angular" rel="noopener noreferrer"&gt;&lt;em&gt;this article&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Focus trapping is handled by the &lt;code&gt;tuiFocusTrap&lt;/code&gt; directive. Since we have drop-downs later in DOM and we can have multiple dialogs open at the same time — we don't care if focus goes farther in the DOM. If it went somewhere prior to dialog though — we return focus back with a few helpers from &lt;code&gt;@taiga-ui/cdk&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="nf"&gt;@HostListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;focusin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;silent&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'$&lt;/span&gt;&lt;span class="k"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nf"&gt;onFocusIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Node&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="nf"&gt;containsOrAfter&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="n"&gt;elementRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&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="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;focusable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getClosestKeyboardFocusable&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="n"&gt;elementRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nativeElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;false&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="n"&gt;elementRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nativeElement&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="n"&gt;focusable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;focusable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focus&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;Blocking page scroll is dealt with by combination of a directive and some logic inside the root component. Root just hides scrollbars when a dialog is open, while Overscroll directive takes care of touch and wheel scroll. There's a &lt;a href="https://developer.mozilla.org/ru/docs/Web/CSS/overscroll-behavior" rel="noopener noreferrer"&gt;CSS rule for overscroll behavior&lt;/a&gt;. However it's not sufficient. It doesn't help when dialog is small enough that it doesn't have its own scroll. That's why we have a directive with some additional logic stopping scroll if it will happen in some patent node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: what else does tui-root do?
&lt;/h2&gt;

&lt;p&gt;As far as portals go — this covers most of it. Let's also take a quick look at what else is bundled with the root component. You saw in the template that it has &lt;code&gt;tui-scroll-controls&lt;/code&gt;. These are custom scrollbars that control global scroll. You may have also noticed named content projections like &lt;code&gt;&amp;lt;ng-content select="tuiOverDialogs"&amp;gt;&amp;lt;/ng-content&amp;gt;&lt;/code&gt;. With those you can slide some content in-between layers of Taiga UI if you need. For example, if you run another library for toasts or dialogs and want them properly placed vertically.&lt;/p&gt;

&lt;p&gt;It also registers several &lt;a href="https://github.com/TinkoffCreditSystems/ng-event-plugins" rel="noopener noreferrer"&gt;event manager plugins&lt;/a&gt; in the DI. You can read about them in a &lt;a href="https://indepth.dev/posts/1153/supercharge-event-management-in-your-angular-application" rel="noopener noreferrer"&gt;dedicated article&lt;/a&gt;. It is important that &lt;code&gt;TuiRootModule&lt;/code&gt; goes after &lt;code&gt;BrowserModule&lt;/code&gt; so they are registered at the right order. But don't worry — if you get it wrong you will see an assertion message in the console.&lt;/p&gt;

&lt;p&gt;That wraps it up for portals and the root component. Taiga UI is open-source and you can check it out on &lt;a href="https://github.com/TinkoffCreditSystems/taiga-ui" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and npm. You can also browse the &lt;a href="https://taiga-ui.dev/" rel="noopener noreferrer"&gt;demo portal&lt;/a&gt; with documentation and play with it using this &lt;a href="https://stackblitz.com/edit/taiga" rel="noopener noreferrer"&gt;StackBlitz starter&lt;/a&gt;. Stay tuned for more articles on interesting features we have!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
