<?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: Riley</title>
    <description>The latest articles on DEV Community by Riley (@rileylnapier).</description>
    <link>https://dev.to/rileylnapier</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%2F513375%2F6a159158-1d92-432a-a744-a6229435ad04.jpeg</url>
      <title>DEV Community: Riley</title>
      <link>https://dev.to/rileylnapier</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rileylnapier"/>
    <language>en</language>
    <item>
      <title>New Courier Inbox: Add a full-featured notification center to your app in minutes</title>
      <dc:creator>Riley</dc:creator>
      <pubDate>Wed, 15 Mar 2023 17:18:49 +0000</pubDate>
      <link>https://dev.to/courier/new-courier-inbox-add-a-full-featured-notification-center-to-your-app-in-minutes-17mn</link>
      <guid>https://dev.to/courier/new-courier-inbox-add-a-full-featured-notification-center-to-your-app-in-minutes-17mn</guid>
      <description>&lt;p&gt;Email and SMS are becoming increasingly busy channels. Sometimes, there’s no better way to reach a user than by sending a message to a notification center right inside of your app. However, building an inbox experience like this, from scratch, was a significant engineering effort.&lt;/p&gt;

&lt;p&gt;Today, we are announcing a major update to &lt;a href="https://www.courier.com/docs/inbox/"&gt;Courier Inbox&lt;/a&gt;, a solution for developers to add an in-app notification center to their web application in a matter of minutes.&lt;/p&gt;

&lt;p&gt;If you’re using the previous version of Inbox, we’ll cover the upgrade steps later in this post.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"With Courier, we added a beautiful inbox and in-app push notifications in a matter of weeks. We used the great looking pre-built component to save even more time. Notifications are not our core competency, so it made complete sense to integrate rather than build out and support our own implementation."&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;James Pipe&lt;/strong&gt;, VP of Product, &lt;a href="https://www.dronedeploy.com/"&gt;DroneDeploy&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is Inbox?
&lt;/h2&gt;

&lt;p&gt;Courier Inbox is an in-app notification center for web applications (and &lt;a href="https://updates.courier.com/board"&gt;mobile inbox coming soon&lt;/a&gt;). Inbox acts as a convenient in-app notification feed with a clean interface where users can view notifications in real time  directly inside your web app. It also lets them view their message history of all past notifications that you’ve sent to them.&lt;/p&gt;

&lt;p&gt;Using in-app notifications allows you to get users’ attention when they are in the application.  This makes your communication with your users more timely and convenient: instead of interrupting them with an email on their phone when they are busy doing something else, you can use an in-app notification to provide information that is relevant to what your users are trying to do right now. Showing notifications within your web application increases user engagement — and provides a more seamless experience, as you can link users directly to relevant parts of the web app within these notifications.&lt;/p&gt;

&lt;p&gt;While many companies are considering building notifications into their web app, not everyone has the time or resources to build a full-fledged notification center. We first implemented Inbox two years ago together with the &lt;a href="https://www.courier.com/blog/react-toast-inbox-notifications/"&gt;web-based pop-up notification&lt;/a&gt; functionality, and customers loved it exactly because it takes so little time to start using it.&lt;/p&gt;

&lt;p&gt;The notifications that customers send via Inbox may include application activity such as discussions, new events, comments, alerts, and reminders, as well as news about feature updates.&lt;/p&gt;

&lt;p&gt;Based on customer feedback, we’re excited to announce improvements to the Inbox functionality. Meet the new Inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the new Inbox
&lt;/h2&gt;

&lt;p&gt;The new Inbox has all the benefits of the original Inbox: it’s fast to implement via pre-built &lt;a href="https://github.com/trycourier/courier-react/tree/main/packages/react-inbox"&gt;Courier JavaScript components&lt;/a&gt;, it offers an intuitive user experience, the design is customizable to your needs, and it natively integrates with the rest of the Courier platform. On top of that, Inbox includes a number of improvements, in terms of both design and functionality.&lt;/p&gt;

&lt;p&gt;On the design side, we took customer feedback on board and simplified how the inbox looks and feels. Specifically, here’s what changed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visually, the inbox now looks more modern so that it fits better into customer apps.&lt;/li&gt;
&lt;li&gt;There are no more separate tabs for read and unread messages — this separation into tabs previously led to confusion. Now everything is displayed more clearly in a single feed.&lt;/li&gt;
&lt;li&gt;Hovering over a message now shows a check mark or cross to mark a message as read or unread, instead of a vertical three-dot menu taking up screen real estate.&lt;/li&gt;
&lt;li&gt;Unread messages are identified by a colorful logo (vs. gray for unread), and the colors are customizable. A colored dot appears at the top showing how many unread messages there are in the inbox.&lt;/li&gt;
&lt;li&gt;Hovering over a message makes the background of that message change color if it is clickable. Short messages where all the text can be viewed at a glance are not clickable and don't change color on hover.
&lt;img src="//images.ctfassets.net/z7iqk1q8njt4/6BJa4hWUJjED61Kdt0CEAR/965e76e0a0ec92213e7fde2402e68683/Courier_-_Inbox_2.0_-_UI_Screenshot.png" alt="New Courier Inbox UI"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notification state is now synchronized between the inbox and other channels. For example, if a notification was sent as in-app and email, reading the email will mark the in-app notification as read.&lt;/p&gt;

&lt;p&gt;Another new feature is message expiration. It’s now possible to set a timeline for the message to expire, say 7 days, and after that time the message will be removed from the inbox. This feature can help avoid a mess of older notifications for users that rarely sign into the web app.&lt;/p&gt;

&lt;p&gt;The advanced branding options, including applying brand settings (we cover this below) and removing the Courier logo, as well as message retention are available on our Developer and Business tiers.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How We Use Internal Hackathons to Create New Product Features</title>
      <dc:creator>Riley</dc:creator>
      <pubDate>Tue, 18 Jan 2022 21:09:39 +0000</pubDate>
      <link>https://dev.to/courier/how-we-use-internal-hackathons-to-create-new-product-features-2lb5</link>
      <guid>https://dev.to/courier/how-we-use-internal-hackathons-to-create-new-product-features-2lb5</guid>
      <description>&lt;p&gt;An internal hackathon is an effective way to engage your employees in short-term collaborative events. It &lt;a href="https://blog.google/inside-google/life-at-google/unlock-your-teams-creativity-running-great-hackathons/#:~:text=A%20hackathon%20shifts,exploring%20that%20occurs."&gt;spurs innovation&lt;/a&gt;, increases employee engagement, explores new feature possibilities, imparts corporate culture, and builds teamwork and collaboration skills. By organizing internal hackathons in your company, your employees can challenge and compete to solve internal or customer problems—which can lead to real-life features in your product.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.courier.com/"&gt;Courier’s&lt;/a&gt; internal hackathons have not only led to a better product and smoother customer experiences, but they have also engaged employees and promoted teamwork. Some of our hackathon projects that made it to production demonstrate the value of giving teams the time and space to innovate this way.&lt;/p&gt;

&lt;p&gt;We do our best to support these hackathons and create the time and space for them, so these events don’t distract employees from their day-to-day work. Our employees, in turn, appreciate the internal hackathons because they get to explore all their ideas and opinions that they don’t have time to work on in their day-to-day jobs. We reflect our culture in our internal hackathons, and, in return, some of the projects make it to production as regular Courier features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Internal Hackathons Represent Our Values at Courier
&lt;/h2&gt;

&lt;p&gt;Our hackathons highlight our &lt;a href="https://www.courier.com/about"&gt;core values&lt;/a&gt;—“have an opinion,” “just f-cking do it,” and “talk to customers.” During these hackathons, team members turn their opinions into experiments, challenge each other, and solve problems. We even have friendly competitions and push each other to win, promote teamwork by sharing Loom videos and presentations, celebrate innovation, etc.&lt;/p&gt;

&lt;p&gt;We also inform the product, sales, and customer service teams about these projects and talk to our existing customers. In the case when a customer shares similar ideas, they quickly chip in: “Oh, we’ve done this in a hackathon before. Let me sync with the engineer and see what it takes to get it production-ready.”&lt;/p&gt;

&lt;p&gt;We host our hackathons twice a year and dedicate a full day each time. Employees are split into two to three technical and non-technical members on a team. Teams record their project demos using Loom, and on the hackathon day, teams give their presentations while the judges watch and vote on the best hackathon project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Examples of a Hackathon Project Becoming a Live Feature
&lt;/h2&gt;

&lt;p&gt;As an engineer at Courier, you feel the pain of some customers. You understand the features they would benefit from but have not yet scoped out technically, or you have no time to build them. Hackathons give you the time and space to experiment.&lt;/p&gt;

&lt;p&gt;Sometimes, this experiment hits home with a common pain point, and we ship it or put it into production. Other times, it is just a fun project. Let’s look at two hackathon projects at Courier that made it to production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Embedded Components Project Turned “Toast and Inbox” Feature
&lt;/h3&gt;

&lt;p&gt;For our very first hackathon, my team experimented with the idea of embedding Courier functionalities in our clients’ websites to give them a better user experience. These components included features to provide an inbox, notification preferences, and a list of recent messages received for our customers.&lt;/p&gt;

&lt;p&gt;For the hackathon, we built an embedded preferences component to allow end-users (our clients’ customers) to control notification preferences. This allowed our clients to let their customers control and manage their preferences. We presented our project and eventually won the first hackathon.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zl2VAR0Ej-o"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Building on top of this, for the second hackathon, my team pushed the idea further to another embedded component to improve the customer experience. For this second hackathon project, we noticed there were a lot of clients with multiple brands asking, “Hey, I love your notification designer, but I need to let my other brands design and change emails, logos, fonts, etc. We want to do that easily without managing every one of them.” So, we built a solution to embed Courier brand designers in an arbitrary website that will allow our clients to update their branding and edit their content seamlessly.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zDRRyh9Mvjw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;After the first two hackathons, we started getting questions from customers wanting to create an inbox to deliver messages to their end-users. So, we looked at the infrastructure of these embedding components’ projects and built &lt;a href="https://www.courier.com/blog/react-toast-inbox-notifications"&gt;react components for Toast and Inbox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Because hackathon projects are not production-ready code, we use the codebase as a blueprint to build out the feature. The timeline of taking a hackathon project to a feature depends on the functionality. Some are relatively easy, while some are difficult depending on the project. Specifically, “Toast and Inbox” was built on top of the technology used for the hackathon but had so many more functionalities, so it took some time to get it out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Column Block Project Turned “Column Element” Feature
&lt;/h3&gt;

&lt;p&gt;At Courier, I am focused on the design and UI side of things—I built a lot of it from scratch. For the third hackathon, my team got creative with our notification block. We wanted to experiment with a new block that would benefit our customers in a different way.&lt;/p&gt;

&lt;p&gt;With the version of the notification designer at that time, you could only make a list of blocks (up and down) but could not put blocks side by side. So, taking some inspiration from &lt;a href="https://sendgrid.com/"&gt;SendGrid&lt;/a&gt; Designer, we created an idea to make two blocks together in our notification designer. Although it was pretty buggy, we got the project out and presented it at the hackathon.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/2LORE_XAZa0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Six months later, &lt;a href="https://uservoice.com/"&gt;UserVoice&lt;/a&gt; wanted to sign in with Courier and mentioned we lacked some functionalities they wanted. Specifically, they wanted to put two blocks next to each other in the notification designer. So, the sales and product team reached out to me, and I went, “Oh yeah, I hacked that together; it was cool but with a few bugs.”&lt;/p&gt;

&lt;p&gt;We had to go back, resurface that code, cut out the buggy scope, clean it up, and build it. But we were able to put it into production in a week and signed the contract with UserVoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving to Developer-Focused Hackathons in the Future
&lt;/h2&gt;

&lt;p&gt;Hackathon projects have helped us stay centered around a better product for our clients’ customers—which is great. In the future, we are shifting to focus these hackathons on improving the developer experience at Courier.&lt;/p&gt;

&lt;p&gt;If our hackathon and processes inspire you, we have some open roles on our &lt;a href="https://jobs.lever.co/trycourier"&gt;careers page&lt;/a&gt;. Come work with us!&lt;/p&gt;

</description>
      <category>hackathon</category>
      <category>features</category>
      <category>productdesign</category>
      <category>productivity</category>
    </item>
    <item>
      <title>React Inbox and React Toast Components for Notifications That Don’t Suck</title>
      <dc:creator>Riley</dc:creator>
      <pubDate>Tue, 31 Aug 2021 15:28:30 +0000</pubDate>
      <link>https://dev.to/courier/introducing-courier-inbox-and-toast-for-notifications-that-don-t-suck-5hj0</link>
      <guid>https://dev.to/courier/introducing-courier-inbox-and-toast-for-notifications-that-don-t-suck-5hj0</guid>
      <description>&lt;p&gt;We are excited to announce the availability of Courier’s newest provider, &lt;a href="https://docs.courier.com/docs/courier-push"&gt;Courier Push&lt;/a&gt;! We have released Inbox and Toast, two open source React components that exemplify the potential future applications of this feature. With Toast, you can send your user a notification within your web application and Inbox allows you to create an embeddable notification repository so that your user can access all past in-app notifications.&lt;/p&gt;

&lt;p&gt;Most importantly, Courier Push allows us the flexibility and customization to do app-to-user communication right. As software users ourselves, we are bombarded with messages constantly, which can...really suck. Yet, notifications are necessary to communicate with users. With Courier Toast and Inbox, developers can support custom notifications for their users’ specificities and communicate through multiple wide-ranging channels while maintaining a single in-app notifications repository. We are particularly excited about all the potential future applications of Courier Push in addition to Toast and Inbox and are looking forward to expanding its uses. &lt;/p&gt;

&lt;p&gt;Here at Courier, we want to improve the integration experience for you, the developer, and the notification experience for your customers. We’ve done this with Courier Toast and Inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Courier Toast and Inbox
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Toast
&lt;/h3&gt;

&lt;p&gt;One of the major tenets of Courier’s product offerings is sending notifications. Receiving them and displaying them in your application is game changing. The ease of implementation makes your job as a developer simple and enables you to build real-time web applications that provide a better user experience for your customers. Your end-users can see customized notifications pop up in your web application through a modular system you can easily customize.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.contentful.com/z7iqk1q8njt4/5c28uDPkC3iIBTT2aAlxI/ae9f06b62b5bc0d40e1d819e1f3dcab0/toast-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="//images.contentful.com/z7iqk1q8njt4/5c28uDPkC3iIBTT2aAlxI/ae9f06b62b5bc0d40e1d819e1f3dcab0/toast-demo.gif" alt="toast-demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Inbox
&lt;/h3&gt;

&lt;p&gt;Alongside Toast messages is a customizable inbox, which is essentially a notification history. This takes the pressure off users to respond immediately, lessening the anxiety around the experience in general. Inside Inbox, a user can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read their messages&lt;/li&gt;
&lt;li&gt;Mark messages as read or unread&lt;/li&gt;
&lt;li&gt;Delete messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="//images.contentful.com/z7iqk1q8njt4/2vyXBqDKYGfuIQj79yAXR9/0e0a255b6f21a02655ec64322cb0d338/inbox-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="//images.contentful.com/z7iqk1q8njt4/2vyXBqDKYGfuIQj79yAXR9/0e0a255b6f21a02655ec64322cb0d338/inbox-demo.gif" alt="inbox-demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Integrate Toast and Inbox in a React App
&lt;/h3&gt;

&lt;p&gt;Let’s walk through how you can integrate Courier Toast and Inbox React Components in a React app. Check out the Courier React Components repository on &lt;a href="https://github.com/trycourier/courier-react"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Install CourierProvider &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@trycourier/react-provider 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;...to handle all of the authentication and integration with the backend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @trycourier/react-provider or npm i @trycourier/react-provider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; At the top level in your React tree, add something that resembles the following code. The Client Key can be found &lt;a href="https://app.courier.com/integrations/courier"&gt;here&lt;/a&gt; and the User Id is the identifier for identifying your user. Note that it will be used later in the API call to courier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CourierProvider } from "@trycourier/react-provider";
import { Toast } from "@trycourier/react-toast";

const MyApp = ({ children }) =&amp;gt; {
  return (
    &amp;lt;CourierProvider clientKey={CLIENT_KEY} userId={USER_ID}&amp;gt;
      &amp;lt;Toast /&amp;gt;
      {children}
    &amp;lt;/CourierProvider&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;N/B: You can add Toast to the frontend anywhere as long as it’s a child of the CourierProvider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Inbox should be added in the application as a child of CourierProvider, but where you want the Bell icon to display. For this example, we will just put it right next to Toast. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn add @trycourier/react-inbox&lt;/code&gt; or &lt;code&gt;npm i @trycourier/react-inbox&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CourierProvider } from "@trycourier/react-provider";
import { Toast } from "@trycourier/react-toast";
import { Inbox } from "@trycourier/react-inbox";

const MyApp = ({ children }) =&amp;gt; {
  return (
    &amp;lt;CourierProvider clientKey={CLIENT_KEY} userId={USER_ID}&amp;gt;
      &amp;lt;Toast /&amp;gt;
      &amp;lt;Inbox /&amp;gt;
      {children}
    &amp;lt;/CourierProvider&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to Customize Toast and Inbox
&lt;/h3&gt;

&lt;p&gt;There are two ways to customize your Inbox and Toast.  First you can use the &lt;code&gt;studio&lt;/code&gt; to customize your application and the components will automatically update when the brand is published.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.contentful.com/z7iqk1q8njt4/Dlr1PTAGFpA51ZmCs5XrA/19a259e26be54a6c8847e091348c43c7/studio-designer.png" class="article-body-image-wrapper"&gt;&lt;img src="//images.contentful.com/z7iqk1q8njt4/Dlr1PTAGFpA51ZmCs5XrA/19a259e26be54a6c8847e091348c43c7/studio-designer.png" alt="studio-designer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second, you can pass properties right into each component.  Each component supports a theme and also supports &lt;a href="https://reactjs.org/docs/render-props.html"&gt;render properties&lt;/a&gt;. Here’s the code for props:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface InboxProps = {
  //Icon Class Name
  className?: string;

  // Default Icon to use if no Icon is present in Message
  defaultIcon?: false | string;

  // Placement of the Bell relative to the Inbox
  placement?: "top" | "left" | "right" | "bottom";

  // Render Props for Custom Rendering
  renderTabs?: React.FunctionComponent&amp;lt;{
    currentTab?: ITab;
    tabs?: ITab[];
  }&amp;gt;;
  renderFooter?: React.FunctionComponent;
  renderHeader?: React.FunctionComponent;
  renderIcon?: React.FunctionComponent&amp;lt;{
    unreadMessageCount?: number;
  }&amp;gt;;
  renderMessage?: React.FunctionComponent&amp;lt;IMessage&amp;gt;;
  renderNoMessages?: React.FunctionComponent;

  // Tab Overrides
  tabs?: Array&amp;lt;ITab&amp;gt;;
  theme?: ThemeObject;

  // Inbox Title Override
  title?: string;
  trigger?: "click" | "hover";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Courier Push opens the doors to perfecting app-to-human communication with its flexibility and potential for customization. Communication is a two-way street that requires not only good messaging, but also a channel and style that works uniquely for a specific type of user using a specific app. With Toast and Inbox, developers can create an effective notifications system that reaches end users when they want, how they want, and the way they want. To learn more, check out the &lt;a href="https://docs.courier.com/docs/courier-push"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We believe that providing contextual notifications from within your app is an opportunity to provide better, more intuitive, and more interesting user experiences. We also believe that if done right, these can take us a long way towards accomplishing our goal of making computer to human communication delightful. This is just the beginning of our investment in solving this problem, so please stay tuned for more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.courier.com/signup"&gt;Check out&lt;/a&gt; Inbox and Toast and let us know what you think! Your feedback helps us to continuously improve.&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>devops</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How We Built React Components for Any Front End</title>
      <dc:creator>Riley</dc:creator>
      <pubDate>Fri, 09 Jul 2021 22:46:42 +0000</pubDate>
      <link>https://dev.to/courier/how-we-built-react-components-for-any-front-end-27gp</link>
      <guid>https://dev.to/courier/how-we-built-react-components-for-any-front-end-27gp</guid>
      <description>&lt;p&gt;Put simply, building and maintaining a completely custom notification system in-house is a pain. It requires a lot of human effort in the beginning and will undoubtedly need to scale at some point. Maintaining a system like this takes away development time from core tasks and business needs.&lt;/p&gt;

&lt;p&gt;To make sure teams don’t need to build an in-house solution for a notification systems problem, we adapted our offering. We created a lightweight solution using React that has a global state and runs independently in the background — so teams can render our components regardless of their tech stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  We built custom Courier components
&lt;/h2&gt;

&lt;p&gt;While React is a popular library, we recognize not everyone uses it, and it might not be as widely used in the future as competing front-end architectures emerge. This is why we wanted to find a way to create custom components that can work in any front end setup with any user interface.&lt;/p&gt;

&lt;p&gt;To solve this we decided to make custom Courier components in React that take inspiration from Web Components. The idea behind &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components"&gt;Web Components&lt;/a&gt; is that they allow developers to build custom, reusable elements where the functionality lives independently from other parts of the codebase.&lt;/p&gt;

&lt;p&gt;This modular setup is what allows for a custom solution that can be implemented anywhere, with any specific user interface, and with any front-end library or framework. Because the logic can live outside the context of your other code, our components can run independently in the background.&lt;/p&gt;

&lt;p&gt;The initial setup is straightforward. You place two script tags in the body (the order of the tags is important). The first script tag holds a small amount of code where you identify configurations like your user with a userId and your Courier clientKey. The second script tag downloads the Courier components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;World&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;courier&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/courier-toast&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;courier&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;inbox&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/courier-inbox&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/section&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&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;courierConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;clientKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{CLIENT_KEY}}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{USER_ID}}&lt;/span&gt;&lt;span class="dl"&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="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&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://courier-components-xvdza5.s3.amazonaws.com/latest.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additional configuration options let you defer the initialization of Courier components, as well as map the configuration for each component you load on the page. The two components you can currently load are toast and inbox. &lt;/p&gt;

&lt;p&gt;Our SDK is exposed on window.courier and is loaded asynchronously. Calling window.courierAsyncInit will let you know Courier has successfully loaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&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;courierAsyncInit&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Courier is Ready!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’d prefer to separate the logic for each component (the toast and inbox components), you can also choose to set window.courierAsyncInit to an array.&lt;/p&gt;

&lt;p&gt;After initialization, window.courier is ready, and you can listen for actions inside the Courier SDK. A small amount of code lets you init the toast component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&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;courierAsyncInit&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="nx"&gt;courier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toast/init&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;courier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can configure the components in two ways:&lt;/p&gt;

&lt;p&gt;with inline HTML attributes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//inline&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;courier&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt; &lt;span class="nx"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/courier-toast&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with window.courierConfig&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;courierConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;autoClose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to use multiple configuration options with a component, window.courierConfig gives you that ability without having to add too many attributes to your HTML element.&lt;/p&gt;

&lt;p&gt;If you do choose to use the inline configuration, you’ll need to make sure you’re always formatting in &lt;a href="https://www.theserverside.com/definition/Kebab-case"&gt;kebab case&lt;/a&gt; since HTML attributes are not case sensitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  We preserved context with React Portals
&lt;/h2&gt;

&lt;p&gt;It’s pretty easy to get up and running with the components. But one hurdle we needed to overcome was making sure the data you need from us is accessible to every Courier React component. And this needs to happen anywhere in your project, regardless of component hierarchy. We make use of &lt;a href="https://reactjs.org/docs/context.html"&gt;React Context&lt;/a&gt; and &lt;a href="https://reactjs.org/docs/portals.html"&gt;React Portals&lt;/a&gt; to inject components anywhere in your DOM.&lt;/p&gt;

&lt;p&gt;If you’re unfamiliar with React Context and React Portals, here’s a quick rundown.&lt;/p&gt;

&lt;h3&gt;
  
  
  React Context
&lt;/h3&gt;

&lt;p&gt;Context allows you to pass props between components without explicitly having to deal with tree structure. This allows for easy access to data regardless of UI requirements. The result is global data accessible by child components that live outside the nesting levels of parent components that contain necessary data.&lt;/p&gt;

&lt;h3&gt;
  
  
  React Portals
&lt;/h3&gt;

&lt;p&gt;The use of a portal allows you to inject a child anywhere into the DOM, retaining the context of the parent node even though it’s outside the standard nesting structure. Even though the portal can be placed randomly in the DOM tree, the portal still retains its context in the React tree. This means events like bubbling will still function normally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting it all together
&lt;/h3&gt;

&lt;p&gt;After the initialization of Courier, we analyze the HTML and find components to dynamically import, making sure not to download any extra components you aren't using. We identify them by HTML tags and then render them inside the context of the Courier SDK. This allows us to then render them wherever you need in the DOM with the Courier context they need.&lt;/p&gt;

&lt;p&gt;So through a combination of React Context and React Portals, we preserve the global state our Courier components rely on. Our toast and inbox components render into a portal, and the portal allows for those components to act as children out of the hierarchy order of the parent. This allows you to render our Courier components into anything that's not in the official React DOM tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  We resourcefully packaged a solution
&lt;/h2&gt;

&lt;p&gt;We’re not here to add code bloat. We purposefully found solutions that guarantee we keep our integration as small as possible.&lt;/p&gt;

&lt;p&gt;We currently have two components you can render, the toast message and the inbox. We're cognizant that library size matters, and while some might see a need to integrate both components, others might only want to integrate one. We also have plans to add more components in the future, so it's important to dynamically load what's needed, not everything.&lt;/p&gt;

&lt;p&gt;By providing a small amount of code for you to implement that handles the automatic download of desired components, we make sure your project remains as small and lightweight as possible. When you load our code, we analyze your HTML to see what components you’ve identified that you need. These components are loaded dynamically and are then cached. This ensures that subsequent renders aren’t refreshing the code.&lt;/p&gt;

&lt;p&gt;We do this with &lt;a href="https://reactjs.org/docs/concurrent-mode-suspense.html"&gt;React Suspense&lt;/a&gt;, which does exactly what it says. It suspends the rendering of React components until a condition is met. In the example below, the portal we’ve created is waiting to see if the toast component has a configuration set up. If it does, we will load it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;toastElement&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="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;courier-toast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toastConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;componentConfigs&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;getAttrsAsJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toastElement&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;CourierSdk&lt;/span&gt;
  &lt;span class="nx"&gt;activeComponents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
    &lt;span class="na"&gt;toast&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toastElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toastElement&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createPortal&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;Suspense&lt;/span&gt; &lt;span class="nx"&gt;fallback&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Toast&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toastConfig&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Suspense&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;      &lt;span class="nx"&gt;toastElement&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/CourierSdk&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a component does need to render, it can do so asynchronously. This implementation method also allows us to scale in the future by adding new components that can be dynamically imported.&lt;/p&gt;

&lt;p&gt;In addition to dynamically imported components, we also keep the bundle small by using &lt;a href="https://preactjs.com/"&gt;Preact&lt;/a&gt;. Preact uses the same ES6 API as React, but Preact is more lightweight and able to load a faster, thinner virtual DOM. We’ve carefully built this implementation so Preact can fully replace all instances of React.&lt;/p&gt;

&lt;p&gt;You can check out the repo &lt;a href="https://github.com/trycourier/courier-react/tree/main/packages/components"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;Courier enables developers to deliver the right message to the right user at the right time. To find out more about Courier’s full offering and see how it can integrate into your stack, check out our &lt;a href="https://docs.courier.com/docs"&gt;docs&lt;/a&gt; and our &lt;a href="https://docs.courier.com/reference/introduction"&gt;API&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Who Knew Email Subjects Are So Complicated</title>
      <dc:creator>Riley</dc:creator>
      <pubDate>Fri, 11 Jun 2021 16:40:27 +0000</pubDate>
      <link>https://dev.to/courier/who-knew-email-subjects-are-so-complicated-27f5</link>
      <guid>https://dev.to/courier/who-knew-email-subjects-are-so-complicated-27f5</guid>
      <description>&lt;p&gt;Did you know that email subjects, by default, only support 127 characters?!  I didn’t, and I ran into a “fun” puzzle of a problem earlier this year when a client of ours noticed a problem with Courier-built emails  in Microsoft Outlook.  Small rendering issues and bugs like this can give the wrong impression to a recipient of an email.  It can make the end user feel the product they are using is poorly planned or not tested.  Not even just that, but not having support for certain characters can prevent you from reaching customers in other languages and countries.&lt;/p&gt;

&lt;p&gt;This is the screenshot we received (note the Black Diamonds): &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1r7LwNyj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ilkc3ud9fe2drc22xbsb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1r7LwNyj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ilkc3ud9fe2drc22xbsb.png" alt="exmaple image"&gt;&lt;/a&gt;&lt;br&gt;
Any guesses why this happened?  Or what the email subject &lt;code&gt;should&lt;/code&gt; be?   Well, the email subject is &lt;strong&gt;French&lt;/strong&gt; and should be “Vèrifiez votre email” (Verify your email).  Let’s dive in, debug, and solve this problem together.&lt;/p&gt;
&lt;h2&gt;
  
  
  How we solved the problem
&lt;/h2&gt;

&lt;p&gt;As any engineer in 2021, the first step was to Google the problem like: black diamond question mark email subject. This didn’t give us great answers, unfortunately. Some of the first results were from a Microsoft forum and the solution was asking people to update their local Outlook configuration thinking the problem was only a local one. The problem with this is that in order for us to be able to help, we would have needed to ask our customers (and all of their customers) to make this update. The lack of ability to reach all these people and clearly explain to them why they needed to do this meant that the solution was a no-go for Courier.&lt;/p&gt;

&lt;p&gt;After digging deeper and making a few keyword changes, I found that this specific character, �, is actually the sign of using a non UTF-8 character when the client expects all characters to be UTF-8. &lt;/p&gt;
&lt;h2&gt;
  
  
  What is UTF-8?
&lt;/h2&gt;

&lt;p&gt;Very basically, UTF-8 characters are the first 128 unicode characters representing a-z, A-Z, and 0-9 characters and keyboard codes (including punctuation, tabs, shift, etc.). This does NOT include accented characters like the ones we had seen used above.  These characters are outside of the first 128 char codes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Encoding to the rescue!
&lt;/h2&gt;

&lt;p&gt;First some background. Emails (and http requests in general) consist of headers and a body.  The &lt;strong&gt;email body&lt;/strong&gt; (HTML) is relatively straightforward.  The other parts of an email include fields like “From:, “To”, “Subject”, etc. are &lt;strong&gt;headers&lt;/strong&gt;.  Headers are where things start to get tricky.  When an email server starts to decode headers, it expects the headers to be UTF-8.  This means you cannot include any characters outside of the first 128 unicode characters as mentioned above.&lt;/p&gt;

&lt;p&gt;To get around this limitation, we can encode our email subjects in base64.  Base64 encoding schemes are commonly used when there is a need to encode binary data, especially when that data needs to be stored and transferred over media that are designed to deal with text.  In layman's terms it takes unicode characters and converts them to UTF-8 readable text.  This does mean the text will be longer, but it allows us to send over all the data we need in a header.&lt;/p&gt;

&lt;p&gt;We can encode base64 like this in Node.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&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;base64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This doesn’t, however, tell the email server that the email subject is base64.  To inform the server the email subject is encoded in base64, we can use this specific format (&lt;strong&gt;RFC&lt;/strong&gt; 1342).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&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;encodedSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;=?UTF-8?B?${buffer.toString("base64");
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sending an email subject like this should “just work,” since this way, the server will decode the string and render it correctly! 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  But wait, there’s more!
&lt;/h2&gt;

&lt;p&gt;Limitations! :(&lt;/p&gt;

&lt;p&gt;We did run into problems with some email providers and the length of the base64 encoded string.  Keep in mind, if I encode the string in base64, check the length, and determine that the length is too high, I cannot just trim the encoded string because it will break the encoding.  I won’t be able to decode the string.&lt;/p&gt;

&lt;p&gt;To solve this, I had to recursively encode the subject and check the string if it was too long.  If it is too long we take the original string, trim it and then re-encode and check the length.  We repeat this process until we get an encoded string at the right length for said email provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxLength&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;number&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hasUnicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&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;subject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxLength&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxLength&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;trim&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;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&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;encodedSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;=?UTF-8?B?${buffer.toString("base64")}?=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// postmark breaks when we send encoded messages &amp;gt; 78&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;maxLength&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;encodedSubject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;maxLength&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;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;maxLength&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;encodedSubject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was our journey into email subjects when we found out that Microsoft Outlook didn’t like certain characters in our email subjects. The process took us from confusion to understanding, and finally building a solution that works for multiple providers. &lt;/p&gt;

&lt;p&gt;It blows my mind that email in 2021 can (still) cause such a headache.  Well, in reality, it is just Microsoft Outlook. This email client is notorious for causing headaches like this. Two of the other most popular clients, Gmail and Superhuman, both handled these email subjects just fine.  I wish this was as easy as saying “we don’t support Internet Explorer,” but so many people still use these old versions of Microsoft Outlook.  So to anyone reading this and building an email application. If anything funky happens, always check and see if it's Microsoft Outlook...and don’t get too frustrated when the solution obtuse and lengthy to implement. &lt;/p&gt;

&lt;p&gt;I’d like to call out these websites which were great and helped us understand and test our solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.sendblaster.com/utf8-email-subject-encoder/"&gt;https://www.sendblaster.com/utf8-email-subject-encoder/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://ncona.com/2011/06/using-utf-8-characters-on-an-e-mail-subject/"&gt;https://ncona.com/2011/06/using-utf-8-characters-on-an-e-mail-subject/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Author: Riley Napier&lt;/p&gt;

</description>
      <category>ux</category>
      <category>email</category>
    </item>
    <item>
      <title>How to use the Shadow DOM to isolate styles on a DOM that isn’t yours</title>
      <dc:creator>Riley</dc:creator>
      <pubDate>Tue, 17 Nov 2020 20:01:34 +0000</pubDate>
      <link>https://dev.to/courier/how-to-use-the-shadow-dom-to-isolate-styles-on-a-dom-that-isn-t-yours-7ad</link>
      <guid>https://dev.to/courier/how-to-use-the-shadow-dom-to-isolate-styles-on-a-dom-that-isn-t-yours-7ad</guid>
      <description>&lt;p&gt;There have been many times in my career of building web apps and frontend experiences that I have needed to embed a widget in a DOM that I did not build or have access to.  For example, embedding e-commerce widgets in a CMS or building chrome extensions to augment a given website.  One of the biggest frustrations I've had is the &lt;code&gt;style collision&lt;/code&gt;.  In my development environment, all the widgets look great but the second I add the widget to a customer’s page… everything is broken! &lt;/p&gt;

&lt;h2&gt;
  
  
  Why does this happen?
&lt;/h2&gt;

&lt;p&gt;The difficulty with embedding widgets in a DOM that you don't own is every DOM is going to reference different default fonts and colors.  It’s normal for a css stylesheet to look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;my-awesome-font&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&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="m"&gt;#eee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I embed my widget into the body of this customer’s page, it will inherit the above styles.  While sometimes this is okay, many times it will break the beautiful widget I designed because I designed the widget with a different font size or padding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Classic solutions
&lt;/h2&gt;

&lt;p&gt;Historically, we have had 2 solutions to this problem:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use an iFrame.&lt;/li&gt;
&lt;li&gt;Be crazy explicit with your styles.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While both solutions can work, they both have rather frustrating aspects you will have to deal with.  Below I'll go over a few examples of what I’ve done in the past and then cover what this blog post is all about – the fancy, new, futuristic way to make composite user interfaces, or the Shadow DOM. &lt;/p&gt;

&lt;h3&gt;
  
  
  Working with iFrames
&lt;/h3&gt;

&lt;p&gt;With an iFrame, I have no control over the element’s size, so the consumer of my widget will have to accurately carve out space in their DOM for my iFrame.  If my widget is dynamic in size, this is going to cause all sorts of problems with scrolling and positioning.&lt;/p&gt;

&lt;p&gt;The second issue we find with iFrames is the communication between the iFrame and the parent.  While I can now use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events" rel="noopener noreferrer"&gt;CustomEvents&lt;/a&gt;, I will need to build out an event system for both the parent and the iFrame context.  This can be frustrating if the client already has a built-in SDK.  It’s basically building a mini SDK for the SDK for iFrame communication.  &lt;/p&gt;

&lt;p&gt;Finally, and maybe the most simplistic issue, is my consumer can’t tweak ANY of the styles in my iFrame.  This can lead to inconsistent user interfaces and is just a bad experience all around.&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%2Fi%2F7uo6vatx0jfy140loegz.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%2Fi%2F7uo6vatx0jfy140loegz.png" alt="You Have No Power Here Meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While iFrames will work, they are outdated, difficult to communicate with, and, if your widget is dynamic in size or you need any kind of customization, &lt;strong&gt;good luck&lt;/strong&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  CSS specificity
&lt;/h2&gt;

&lt;p&gt;The more common approach I have taken is to just be super specific with my CSS.  So namespace everything!  This can be tedious and will most likely need to be tweaked for each new client integrating your components. The QA process for pushing out an update to the widget is going to be difficult too.  There are so many ways clients can use CSS and have it break your integration.&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%2Fi%2F1eu6cmv5s2arq6mozuh6.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%2Fi%2F1eu6cmv5s2arq6mozuh6.png" alt="Shocked Pikachu Meme"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Ok, so if I don’t want to use an iFrame or be anal about my CSS, what can I do?&lt;/p&gt;




&lt;h2&gt;
  
  
  Enter the Shadow DOM!
&lt;/h2&gt;

&lt;p&gt;Wow, that sounds spooky… What is the Shadow DOM you ask? It’s an API for DOM encapsulation and we all know how important encapsulation is.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Shadow DOM allows hidden DOM trees to be attached to elements in the regular DOM tree — this Shadow DOM tree starts with a shadow root underneath which can be attached to any elements you want in the same way as the normal DOM.&amp;gt; -&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" rel="noopener noreferrer"&gt;Using Shadow DOM&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The most basic approach to creating a shadow is to attach it to any DOM element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shadow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;closed&lt;/span&gt;&lt;span class="err"&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 mode &lt;code&gt;open&lt;/code&gt; or &lt;code&gt;closed&lt;/code&gt; allows you to specify whether or not the page’s JavaScript can interact with the Shadow DOM.  Open means it can interact and closed means it cannot.&lt;/p&gt;

&lt;p&gt;After I’ve created my shadow element, I can append to it just like any normal DOM node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shadow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;closed&lt;/span&gt;&lt;span class="err"&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;styleNode&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="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="err"&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;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    background: blue;
    font-size: 18px;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;shadow&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="nx"&gt;styleNode&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;contentNode&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="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;contentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Hello World`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;shadow&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="nx"&gt;contentNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code will create a shadow node, append a node style to the Shadow DOM, and append a div saying Hello World. The style will now be isolated, only affecting the shadow tree and not contaminating the parent. Success!&lt;/p&gt;

&lt;h2&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%2Fi%2Fg6ylinoa4bdawsaz2ipi.png" alt="That Moment When Meme"&gt;
&lt;/h2&gt;

&lt;p&gt;However, the above example is very verbose and simple and is showing us just the bare metal implementation of the Shadow DOM.  It’s only scratching the surface of what the Shadow DOM can do.  It’s not all that complicated and it’s pretty well supported right now.&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%2Fi%2Fni4jdk6m9r64h5p2bmi5.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%2Fi%2Fni4jdk6m9r64h5p2bmi5.png" alt="Shadow DOM Compatibility Chart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Shadow DOM with React
&lt;/h2&gt;

&lt;p&gt;I’d like to take a quick moment to highlight a really useful package that I’ve used in the past and really gave me the feeling of “WOW, I might actually be able to use this in production.”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/react-shadow" rel="noopener noreferrer"&gt;React Shadow&lt;/a&gt; makes working with the shadow DOM with React easy as pie!  The example I used above with &lt;code&gt;react-shadow&lt;/code&gt; will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;root&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;react-shadow&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="k"&gt;default &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;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;World&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="nx"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/style&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/root.div&lt;/span&gt;&lt;span class="err"&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;Now, if that isn’t magic, I don’t know what else is. So, take a step with me into the future. Let’s not be afraid of our Shadow DOM and let’s make beautiful composite user experiences together!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgz0ztw7xek956qzihy8c.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%2Fi%2Fgz0ztw7xek956qzihy8c.png" alt="Sponge Bob Magic Meme"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>css</category>
      <category>shadowdom</category>
    </item>
  </channel>
</rss>
