<?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>Forem: Josh Kuttler</title>
    <description>The latest articles on Forem by Josh Kuttler (@joshk2).</description>
    <link>https://forem.com/joshk2</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%2F223146%2F33dfb171-cefd-4b5d-bbc9-4df274224991.jpeg</url>
      <title>Forem: Josh Kuttler</title>
      <link>https://forem.com/joshk2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/joshk2"/>
    <language>en</language>
    <item>
      <title>How to Manage and Create Composable Email Templates with Components</title>
      <dc:creator>Josh Kuttler</dc:creator>
      <pubDate>Thu, 07 May 2026 13:09:50 +0000</pubDate>
      <link>https://forem.com/joshk2/how-to-manage-and-create-composable-email-templates-with-components-ob9</link>
      <guid>https://forem.com/joshk2/how-to-manage-and-create-composable-email-templates-with-components-ob9</guid>
      <description>&lt;p&gt;Every product team eventually hits the same wall with email: a &lt;code&gt;welcome.html&lt;/code&gt; file ballooning into a 1,200-line monolith, copy-pasted styles across templates that never quite match, a marketing tweak that breaks billing emails, and an A/B test that takes a week to ship because the "templating engine" lives in a folder no one wants to touch.&lt;/p&gt;

&lt;p&gt;Email is one of the last places in modern product engineering where we still tolerate this. We componentized our UI years ago. We componentized our backends. But our transactional and lifecycle emails are still strings of HTML glued together inside a service.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://bit.cloud/" rel="noopener noreferrer"&gt;Bit&lt;/a&gt;, we manage every email template - welcome, billing, organization invites, password resets, notifications - as independent, versioned, composable components. Each piece of an email (a title, a paragraph, a CTA button, a card, a footer) is its own component. Each template (welcome, payment-failed, scope-invite) composes those pieces.&lt;/p&gt;

&lt;p&gt;This post walks through how we got there, and how you can do the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "composable" emails matter
&lt;/h2&gt;

&lt;p&gt;Emails have all the same problems as UI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency.&lt;/strong&gt; Every email needs to look like the same product. The same brand color on the CTA. The same paragraph spacing. The same footer copy and unsubscribe link.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bit.cloud/products/components" rel="noopener noreferrer"&gt;&lt;strong&gt;Reuse.&lt;/strong&gt;&lt;/a&gt; "Action button" exists in 30 templates. "Card with content" exists in 20. The footer exists in all of them.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bit.cloud/products/change-requests" rel="noopener noreferrer"&gt;&lt;strong&gt;Change management.&lt;/strong&gt;&lt;/a&gt; When the brand color changes, or the footer text changes, or the unsubscribe URL changes, you don't want to grep 30 files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing.&lt;/strong&gt; You want to preview a template visually, in isolation, with mock data - the same way you preview a React component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ownership.&lt;/strong&gt; Billing owns billing emails. People owns invite emails. Marketing owns lifecycle emails. They shouldn't all live in one folder owned by no one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Emails are UI. The fact that they render in Gmail instead of a browser doesn't change the engineering problem. So we apply the same pattern: small, independent components, composed into larger ones, distributed across teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;Our email system is built from three layers, each living in its own namespace:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI primitives&lt;/strong&gt; - the small building blocks: &lt;code&gt;email-title&lt;/code&gt;, &lt;code&gt;email-paragraph&lt;/code&gt;, &lt;code&gt;email-link&lt;/code&gt;, &lt;code&gt;email-action&lt;/code&gt;, &lt;code&gt;email-card&lt;/code&gt;. Each is a component that returns a string of inline-styled HTML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Templates&lt;/strong&gt; - composed emails: &lt;code&gt;welcome-email&lt;/code&gt;, &lt;code&gt;password-reset-request&lt;/code&gt;, &lt;code&gt;billing/payment-failed&lt;/code&gt;, &lt;code&gt;org/org-invite&lt;/code&gt;. Each imports the primitives it needs and renders a full HTML document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aspect&lt;/strong&gt; - a single &lt;code&gt;email&lt;/code&gt; aspect that exposes a slot-based API. Any service can register an email provider (Resend, SES, SendGrid) and any feature can request to send an email through it.&lt;/p&gt;

&lt;p&gt;Here is the full layout in our emails scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;teambit.emails/
├── aspects/
│   ├── email        ← the platform aspect (slot + sendEmail API)
│   └── resend       ← a provider implementation
├── ui/
│   ├── email-title
│   ├── email-paragraph
│   ├── email-link
│   ├── email-action
│   ├── email-card
│   └── get-started
└── templates/
    ├── base-email   ← the shared layout
    ├── welcome-email
    ├── email-confirmation
    ├── password-reset-request
    ├── password-reset-confirmed
    ├── email-notification
    ├── contact-sales
    ├── ...
    ├── billing/
    │   ├── payment-success
    │   ├── payment-failed
    │   └── ...
    ├── org/
    │   ├── org-invite
    │   └── ...
    └── scope/
        └── scope-invite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every node in that tree is an &lt;a href="https://bit.dev/docs/getting-started/collaborate/snap-component-changes" rel="noopener noreferrer"&gt;independently versioned Bit component&lt;/a&gt;. &lt;code&gt;email-action&lt;/code&gt; can release a v1.2 with a new prop. &lt;code&gt;welcome-email&lt;/code&gt; can pick up that release on its own schedule. &lt;code&gt;billing/payment-failed&lt;/code&gt; doesn't have to know either exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 - A UI primitive
&lt;/h2&gt;

&lt;p&gt;Let's start at the bottom. Here is the entire implementation of &lt;code&gt;EmailAction&lt;/code&gt; - the CTA button used across every template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EmailActionProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secondary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;link&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;marginBottom&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;EmailAction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;EmailActionProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#6c5ce7&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ffffff&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;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#1d1c1d&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;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #e0e0e0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div style="margin-bottom: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;marginBottom&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;; text-align: left;"&amp;gt;
      &amp;lt;a
        href="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"
        target="_blank"
        style="
          display: inline-block;
          padding: 12px 24px;
          background: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
          color: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
          border: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;border&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
          border-radius: 6px;
          font-weight: 600;
          text-decoration: none;
          font-family: 'Lato', 'Helvetica', 'Arial';
        "
      &amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/a&amp;gt;
    &amp;lt;/div&amp;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;A few things worth noticing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It returns a string. Email is HTML - there is no DOM, no React reconciler. We're building strings, but with the same component model.&lt;/li&gt;
&lt;li&gt;All styles are inline. Email clients (especially Gmail and Outlook) strip &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags and ignore most CSS files. The component is the only place styles can live, so the component owns them.&lt;/li&gt;
&lt;li&gt;The API is typed. &lt;code&gt;priority&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt;, &lt;code&gt;link&lt;/code&gt;, &lt;code&gt;marginBottom&lt;/code&gt; are all explicit props. Consumers get autocomplete and type errors, exactly as if this were a React component.&lt;/li&gt;
&lt;li&gt;It has no dependencies on other email components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;email-paragraph&lt;/code&gt;, &lt;code&gt;email-title&lt;/code&gt;, &lt;code&gt;email-link&lt;/code&gt;, &lt;code&gt;email-card&lt;/code&gt; follow the same shape: typed props in, HTML string out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - A shared base layout
&lt;/h2&gt;

&lt;p&gt;Every email needs the same outer shell: the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; document, the brand logo at the top, the footer with the unsubscribe link. That is &lt;code&gt;base-email&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Footer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./footer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FooterProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./footer&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="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;BaseEmailProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;FooterProps&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;BaseEmail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unsubscribeLink&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;BaseEmailProps&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="s2"&gt;`&amp;lt;html lang="en"&amp;gt;
    &amp;lt;head&amp;gt;
      &amp;lt;meta name="viewport" content="width=device-width"&amp;gt;
      &amp;lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
      &amp;lt;div style="background: #f7f7f7; font-family: 'Lato', 'Helvetica', 'Arial'; font-size: 16px; line-height: 16px; color: #1d1c1d;"&amp;gt;
        &amp;lt;div style="max-width: 600px; margin: 14px auto; padding: 10px;"&amp;gt;
          &amp;lt;div style="width: 100%; margin-bottom: 32px; text-align: left;"&amp;gt;
            &amp;lt;a href="https://bit.cloud" target="_blank" style="text-decoration: none;"&amp;gt;
              &amp;lt;img src="https://storage.googleapis.com/static.bit.dev/brands/bit-logo-min.png" style="width: 60px; height: 60px;" /&amp;gt;
            &amp;lt;/a&amp;gt;
          &amp;lt;/div&amp;gt;
          &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;children&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="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;unsubscribeLink&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="s2"&gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/body&amp;gt;
  &amp;lt;/html&amp;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;&lt;code&gt;BaseEmail&lt;/code&gt; takes &lt;code&gt;children&lt;/code&gt; as a string - the rendered body of the specific template - and wraps it in the brand layout. The footer is another component injected by the base. Update the brand color or the footer copy here once, and every template inherits it on its next install.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Composing a template
&lt;/h2&gt;

&lt;p&gt;Now the fun part. Here's &lt;code&gt;WelcomeEmail&lt;/code&gt; - the actual email that goes to every new Bit Cloud user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BaseEmail&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@teambit/emails.templates.base-email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;EmailAction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@teambit/emails.ui.email-action&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;EmailTitle&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@teambit/emails.ui.email-title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;EmailParagraph&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@teambit/emails.ui.email-paragraph&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GetStarted&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./get-started&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="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;WelcomeEmailProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;WelcomeEmail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;WelcomeEmailProps&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="nc"&gt;BaseEmail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div style="background: #ffffff;"&amp;gt;
      &amp;lt;img src="https://static.bit.dev/emails/welcome-to-bit-cloud.png" width="100%" height="auto"&amp;gt;
      &amp;lt;div style="padding: 32px 20px 64px;"&amp;gt;

        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;EmailParagraph&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Hey &amp;lt;span style="font-weight: bold;"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,&amp;lt;/span&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px&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="s2"&gt;

        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;EmailParagraph&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Welcome to Bit Cloud, the AI-powered platform for building production-grade software.&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="s2"&gt;

        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;EmailTitle&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="s1"&gt;Build from Scratch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="s2"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;EmailParagraph&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Describe your app with a prompt. Hope AI builds it, validates it, and deploys it instantly.&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="s2"&gt;

        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;EmailTitle&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="s1"&gt;Modernize Legacy Code&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})}&lt;/span&gt;&lt;span class="s2"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;EmailParagraph&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generate modern packages from your legacy projects. Renew your stack one component at a time.&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="s2"&gt;

        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;EmailAction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Prompt for Production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://bit.cloud/hope&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;32px&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="s2"&gt;

        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;GetStarted&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;

      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;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;That's the entire email. Notice what isn't there: no inline styles, no HTML boilerplate, no footer markup, no logo URL. All of that lives in &lt;code&gt;BaseEmail&lt;/code&gt; and the primitives. This file is purely the content of the welcome email - the words, the structure, the order of the sections.&lt;/p&gt;

&lt;p&gt;Compare that to a typical 800-line &lt;code&gt;welcome.html&lt;/code&gt; and the difference is immediate. Three months from now, when the marketing team wants to add a section about a new feature, they will edit this file. No one will need to touch &lt;code&gt;base-email&lt;/code&gt;, &lt;code&gt;email-action&lt;/code&gt;, or &lt;code&gt;email-title&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Sending it through a service
&lt;/h2&gt;

&lt;p&gt;So far everything is just functions that return HTML strings. The last piece is the runtime: something that takes a rendered template and actually puts it in someone's inbox.&lt;/p&gt;

&lt;p&gt;We keep this as a small, standalone email service that expose a single &lt;code&gt;sendEmail&lt;/code&gt; method that any feature in the app can call.&lt;/p&gt;

&lt;p&gt;And anywhere in the app - billing, onboarding, notifications - you render a template and hand it to the service:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WelcomeEmail&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@teambit/emails.templates.welcome-email&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;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WelcomeEmail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jane&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;emailService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jane@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello@bit.cloud&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Welcome to Bit Cloud&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;html&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;Three things are worth pointing out about this seam:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Templates don't know which provider sends them. &lt;code&gt;WelcomeEmail&lt;/code&gt; returns a string. It has no idea Resend exists.&lt;/li&gt;
&lt;li&gt;Providers don't know which templates they send. &lt;code&gt;EmailProvider&lt;/code&gt; only sees &lt;code&gt;EmailData&lt;/code&gt;. To it, every email looks the same.&lt;/li&gt;
&lt;li&gt;The service is the only thing that knows about both. Swap Resend for SES tomorrow by registering a different provider - no template has to change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is dependency inversion in plain English: the templates and the providers depend on a small interface in the middle, never on each other. It's the same pattern you'd use for a payments service, a storage service, or a search service. Email is no different.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're building this inside a Bit Harmony platform, this "service" is exactly what we call an aspect - same idea, just with a slot-based registration API so providers can plug themselves in automatically. If that's not your world, a plain class with a registerProvider method works just as well.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What this gets you in practice
&lt;/h2&gt;

&lt;p&gt;A few concrete wins:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Brand changes are one snap.&lt;/strong&gt; When we updated our primary brand color, we changed it in &lt;code&gt;email-action&lt;/code&gt; and snapped a new version. Every template automatically picked it up on the next install. No grep, no missed templates, no inconsistent buttons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teams own their templates.&lt;/strong&gt; Billing owns &lt;code&gt;templates/billing/*&lt;/code&gt;. Organization owns &lt;code&gt;templates/org/*&lt;/code&gt;. They don't ask permission to ship a copy change. They snap their own component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Templates are previewable.&lt;/strong&gt; Each template is a Bit component, which means it has compositions. Drop it on the dev server (&lt;code&gt;bit start&lt;/code&gt;) and you get a live preview with mock props - the same workflow as previewing a React component. We can iterate on the welcome email without sending a single real message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type-safety end to end.&lt;/strong&gt; &lt;code&gt;WelcomeEmail({ username })&lt;/code&gt; is a typed function call. If the template starts requiring a new prop, the call site fails to compile. No more "I forgot to pass the user's first name and the email said &lt;code&gt;Hi undefined&lt;/code&gt;," stories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Versioned and diffable.&lt;/strong&gt; Every change is a snap. Every snap has a diff. We can see who changed &lt;code&gt;base-email&lt;/code&gt; last week and why. We can roll back a single template without touching anything else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reuse across products.&lt;/strong&gt; The same &lt;code&gt;email-action&lt;/code&gt;, &lt;code&gt;email-card&lt;/code&gt;, and &lt;code&gt;email-paragraph&lt;/code&gt; we use in transactional emails are also used in marketing emails, in admin notifications, in our agent-driven hope-finished-generating email. One vocabulary, many products.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to start, in your own workspace
&lt;/h2&gt;

&lt;p&gt;You have two ways to get this running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fast way — ask Hope to build it for you&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bit.cloud/products/hope-ai" rel="noopener noreferrer"&gt;Hope AI&lt;/a&gt; is the AI builder on &lt;a href="https://bit.cloud/" rel="noopener noreferrer"&gt;Bit Cloud&lt;/a&gt;. Open a new chat and try a prompt like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create a composable email system in a new emails scope. Use the frontend.html/envs/html-cjs-env environment for every component. I want primitive components for title, paragraph, link, and a CTA action button — each returning inline-styled HTML strings. Add a base-email template that wraps content in our brand layout with a footer. Then create three templates: welcome-email, password-reset, and payment-failed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hope will plan the scope, generate every component with the right environment, wire the dependencies, and let you preview each template visually before you snap. From there you can ask follow-ups — "add a billing/subscription-cancelled template", "swap the brand color across all primitives", "add an SES provider" — and Hope will handle the changes the same way.&lt;/p&gt;

&lt;p&gt;Here's what Hope produced from a single prompt:&lt;br&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%2F9wm9rr29pi2fkd7unhu7.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%2F9wm9rr29pi2fkd7unhu7.png" alt="Hope AI" width="800" height="416"&gt;&lt;/a&gt;&lt;br&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%2Fnzsdplbxgardt8xgb1uw.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%2Fnzsdplbxgardt8xgb1uw.png" alt="Hope AI" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The manual way — step by step&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you'd rather build it yourself first to feel the pattern, here's the full path with the commands you'll actually run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Set up the workspace and enable the HTML env&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Email components aren't React components — they render to plain HTML strings, server-side, and never touch the DOM. We use &lt;code&gt;frontend.html/envs/html-cjs-env&lt;/code&gt;, which compiles to CommonJS so the templates can be required straight from any Node service that needs to send mail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Initialize a workspace if you don't have one&lt;/span&gt;
bit init my-emails-workspace
&lt;span class="nb"&gt;cd &lt;/span&gt;my-emails-workspace

&lt;span class="c"&gt;# Install the HTML env so its generator templates become available&lt;/span&gt;
bit &lt;span class="nb"&gt;install&lt;/span&gt; @frontend/html.envs.html-cjs-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the env to the generator section of your &lt;code&gt;workspace.jsonc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"teambit.generator/generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"envs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"frontend.html/envs/html-cjs-env"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;bit templates&lt;/code&gt; to confirm — you should see the &lt;code&gt;html&lt;/code&gt; template listed.&lt;/p&gt;

&lt;p&gt;Configure your scope, every Bit component lives in a scope — that's what shows up in the package name (@your-org/emails.ui.email-title) and what teams use to find your work. Set it once in &lt;code&gt;workspace.jsonc&lt;/code&gt; and every new component you create will belong to it automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"teambit.workspace/workspace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;every&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;created&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;under&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;scope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"defaultScope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-org.emails"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't have a scope yet, create one at &lt;a href="https://bit.cloud/create-scope" rel="noopener noreferrer"&gt;bit.cloud/create-scope&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Create your primitives&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start with three: a title, a paragraph, a CTA button. Don't try to model every possible piece up front — add new primitives only when a template actually needs one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bit create html ui/email-title &lt;span class="nt"&gt;--env&lt;/span&gt; frontend.html/envs/html-cjs-env
bit create html ui/email-paragraph &lt;span class="nt"&gt;--env&lt;/span&gt; frontend.html/envs/html-cjs-env
bit create html ui/email-action &lt;span class="nt"&gt;--env&lt;/span&gt; frontend.html/envs/html-cjs-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each one is a tiny function: typed props in, inline-styled HTML string out. Push every style into the primitive itself — Gmail and Outlook strip &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags, so the component is the only place styles can live.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Build a base layout&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One component that renders the  document, the brand header, and the footer. It takes children as a string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bit create html templates/base-email &lt;span class="nt"&gt;--env&lt;/span&gt; frontend.html/envs/html-cjs-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Write your first template&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compose the primitives inside the base. Resist the urge to put inline styles here — this file is purely the content of the email.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bit create html templates/welcome-email &lt;span class="nt"&gt;--env&lt;/span&gt; frontend.html/envs/html-cjs-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Preview, snap, and reuse&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Preview every template visually with mock props&lt;/span&gt;
bit start

&lt;span class="c"&gt;# When you're happy, validate, snap, and export&lt;/span&gt;
bit validate
bit snap &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s2"&gt;"initial composable email system"&lt;/span&gt;
bit &lt;span class="nb"&gt;export&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the first template is in place, the second one is a 10-minute job. By template five, you'll wonder how you ever did it differently.&lt;/p&gt;

&lt;p&gt;You don't need a "framework" for this. You don't need MJML, Maizzle, or React Email. The pattern is the point: small components, composed into larger ones, versioned independently, owned by the teams that care about them.&lt;/p&gt;

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

&lt;p&gt;Email is the last unrefactored corner of most product codebases. It doesn't have to be. The same composability that transformed how we ship UI works just as well for what we ship to inboxes. The result is faster iteration, fewer regressions, clearer ownership, and emails that actually look like they came from the same product.&lt;/p&gt;

&lt;p&gt;Treat your emails like components. Your future self - and your marketing team - will thank you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by Josh Kuttler, Software Engineer at &lt;a href="https://bit.cloud" rel="noopener noreferrer"&gt;Bit&lt;/a&gt; — building the composable web.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let's connect — I'd love to hear how you're handling emails (or anything composable) in your stack:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐦 &lt;strong&gt;X:&lt;/strong&gt; &lt;a href="https://x.com/JoshKuttler" rel="noopener noreferrer"&gt;@JoshKuttler&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💼 &lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/josh-kuttler/" rel="noopener noreferrer"&gt;josh-kuttler&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;If this post helped, a ❤️ or a follow on dev.to means a lot — and lets me know what to write about next.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How to Publish React Native Components for Reuse</title>
      <dc:creator>Josh Kuttler</dc:creator>
      <pubDate>Sun, 07 Jun 2020 11:59:47 +0000</pubDate>
      <link>https://forem.com/joshk2/how-to-publish-react-native-components-for-reuse-5g54</link>
      <guid>https://forem.com/joshk2/how-to-publish-react-native-components-for-reuse-5g54</guid>
      <description>&lt;p&gt;Publishing and reusing React Native components across applications with Bit.&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%2Fyymd3rghv1pfsgc903ha.jpeg" 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%2Fyymd3rghv1pfsgc903ha.jpeg" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React Native components, just like ReactJS, are built for reuse.&lt;/p&gt;

&lt;p&gt;Reusing React native components across applications speeds up your development, makes it easier to maintain your codebase, and makes sure that your users will enjoy a consistent experience at every touchpoint.&lt;/p&gt;

&lt;p&gt;However, publishing many components for reuse can also be a challenge that requires a lot of work, documentation, and teamwork. This work can be streamlined, simplified, and scaled using new tools built for this purpose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/teambit/bit" rel="noopener noreferrer"&gt;Bit&lt;/a&gt; is an open-source tool that helps you develop, publish and manage components across many applications. It is completed by the &lt;a href="https://bit.dev" rel="noopener noreferrer"&gt;bit.dev platform&lt;/a&gt;, where all your components are organized, documented, and become available to reuse. It streamlines the process of publishing and documenting JS 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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ANj2EzGOskF51B5AKuR-szw.gif" 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%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ANj2EzGOskF51B5AKuR-szw.gif" alt="Example: Exploring React components published on [Bit](https://bit.dev)" width="600" height="316"&gt;&lt;/a&gt;&lt;em&gt;Example: Exploring React components published on &lt;a href="https://bit.dev" rel="noopener noreferrer"&gt;Bit&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this post, I’ll show how to use &lt;a href="https://bit.dev" rel="noopener noreferrer"&gt;Bit&lt;/a&gt; to &lt;em&gt;independently&lt;/em&gt; version, publish, and document React Native components from, essentially, any React Native app.&lt;/p&gt;

&lt;p&gt;My published components will then be available on a public collection on &lt;a href="https://bit.dev" rel="noopener noreferrer"&gt;Bit.dev&lt;/a&gt;, where others can read their docs, try them in a live playground, and install them using NPM, Yarn, or Bit. This collection can be gradually expanded to create a fully functional reusable system of 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%2F4ufveuh9lvabq5y668ep.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%2F4ufveuh9lvabq5y668ep.png" width="390" height="811"&gt;&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%2Fcdn-images-1.medium.com%2Fmax%2F3932%2F1%2AnzH8a6ZOtuhA0GDGU2vSsQ.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%2Fcdn-images-1.medium.com%2Fmax%2F3932%2F1%2AnzH8a6ZOtuhA0GDGU2vSsQ.png" alt="The [“My Store” app](https://github.com/JoshK2/mystore) and its [published components](https://bit.dev/joshk/mystore-app-components)" width="800" height="311"&gt;&lt;/a&gt;&lt;em&gt;The &lt;a href="https://github.com/JoshK2/mystore" rel="noopener noreferrer"&gt;“My Store” app&lt;/a&gt; and its &lt;a href="https://bit.dev/joshk/mystore-app-components" rel="noopener noreferrer"&gt;published components&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a React Native Store App: “My Store”
&lt;/h2&gt;

&lt;p&gt;Demo project on GitHub:&lt;br&gt;
&lt;a href="https://github.com/JoshK2/mystore" rel="noopener noreferrer"&gt;JoshK2/mystore&lt;br&gt;
A simple products list store build with React Native components and then shared them to a collection on bit.dev.&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx react-native init mystore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any store needs some way to present its products. To make that happen, I’ll create 3 components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Product: Shows the image, title, description and price.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Button: Adds the product to the shopping cart.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Products list: Receive a list of products and displays them vertically.&lt;/p&gt;

&lt;p&gt;src&lt;br&gt;
└── components&lt;br&gt;
    ├── button.js&lt;br&gt;
    ├── product.js&lt;br&gt;
    └── products-list.js&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, the “Button” component:&lt;/p&gt;

&lt;p&gt;I’ve used prop-types for all my components. That will serve two purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;As with any other use of prop-types, my components will be safer to use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bit will use my prop-types definitions to create documentation for each component. That would also be the case with TypeScipt and JSDocs (alternatively, you can add an .md file to your component).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2F8wyz8emrdsec8ehokrr3.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%2F8wyz8emrdsec8ehokrr3.png" width="800" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing the “My Store” Components to Bit
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install Bit globally.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install bit-bin --global
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Initialize a new “Bit Workspace” (in the project’s root directory).
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bit init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Track all components under the components directory (similar to git add ). While doing this, Bit will automatically define each unit as a “component” with all its relevant files, dependencies etc. This is very useful when you seek to develop and publish many components in the same repository.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bit add src/components/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Configure my tracked components to use the &lt;a href="https://bit.dev/bit/envs/compilers/react-native" rel="noopener noreferrer"&gt;React Native compiler&lt;/a&gt; available in Bit’s &lt;a href="https://bit.dev/bit/envs" rel="noopener noreferrer"&gt;“ENVs” collection&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Wit hBit, we configure a compiler to decouple the soon-to-be-published components from the app’s build setup. This way, we make sure they’ll work in other future environments.&lt;/p&gt;

&lt;p&gt;That’s done by importing the compiler as I would with any other published component and adding the -c flag to set it as a compiler (this will be added to Bit’s configurations in package.json )&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bit import bit.envs/compilers/react-native -c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Bit lets you version each component independently, which is &lt;a href="https://blog.bitsrc.io/versioning-independent-ui-components-why-and-how-7ea60d8be5f2" rel="noopener noreferrer"&gt;great for reuse at a slightly larger scale&lt;/a&gt;. Tag all components to record all changes and lock versions. The -a flag marks all tracked components. We could also specify the new version number but, here, I’ve left that to Bit.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bit tag -a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you run bit status, you’ll see that each component got its own version. Remember that Bit tracks every component’s dependencies as well as changes to its code, so from now on when you make a change, Bit will help you tag and bump the version of all components impacted by the change.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Publish all tracked components.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For this, I’ll first head over to &lt;a href="https://bit.dev" rel="noopener noreferrer"&gt;Bit.dev&lt;/a&gt;, open a free account, and create a new component collection. I’ll name this collection “mystore-app-components”. Once done, I’ll continue to publish them to my new collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bit export joshk.mystore-app-components
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My components are now published on Bit! 🎉&lt;br&gt;
&lt;a href="https://bit.dev/joshk/mystore-app-components" rel="noopener noreferrer"&gt;mystore-app-components by joshk · Bit&lt;br&gt;
A demo store components build with React Native - 3 Javascript components. Examples: product , products-list , button&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%2Fcdn-images-1.medium.com%2Fmax%2F3654%2F1%2A5wA3uXU7pFW_fty-lVZ8Ig.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%2Fcdn-images-1.medium.com%2Fmax%2F3654%2F1%2A5wA3uXU7pFW_fty-lVZ8Ig.png" alt="[https://bit.dev/joshk/mystore-app-components](https://bit.dev/joshk/mystore-app-components)" width="800" height="400"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://bit.dev/joshk/mystore-app-components" rel="noopener noreferrer"&gt;https://bit.dev/joshk/mystore-app-components&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All my components are now reusable, and I can share them between the different applications that I or my team are building.&lt;/p&gt;

&lt;p&gt;You can browse through the component pages, see each component rendered in Bit’splayground (using an example code I’ve written).&lt;/p&gt;

&lt;p&gt;You can choose to either &lt;strong&gt;install&lt;/strong&gt; components like any other package using NPM/Yarn or to “clone” components into your project using bit import .&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imported&lt;/strong&gt; or “cloned” components (&lt;code&gt;bit import&lt;/code&gt;) can be modified in any codebase using them and pushed back with a bumped version. That makes collaboration possible even across repositories.&lt;/p&gt;

&lt;p&gt;Happy coding and sharing!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>react</category>
      <category>reuse</category>
      <category>sharing</category>
    </item>
    <item>
      <title>A new version of React Native compiler for Bit</title>
      <dc:creator>Josh Kuttler</dc:creator>
      <pubDate>Thu, 23 Jan 2020 17:00:46 +0000</pubDate>
      <link>https://forem.com/joshk2/a-new-version-of-react-native-compiler-for-bit-23f3</link>
      <guid>https://forem.com/joshk2/a-new-version-of-react-native-compiler-for-bit-23f3</guid>
      <description>&lt;p&gt;I just published a new version of React Native compiler for Bit&lt;br&gt;
and I would appreciate some feedback.&lt;/p&gt;

&lt;p&gt;You can write in the comments section, links to React Native components you exported.&lt;/p&gt;

&lt;p&gt;To Install and use the compiler:&lt;br&gt;
&lt;a href="https://bit.dev/bit/envs/compilers/react-native" rel="noopener noreferrer"&gt;https://bit.dev/bit/envs/compilers/react-native&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stars to the repository will be welcome 😉💫 &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/teambit" rel="noopener noreferrer"&gt;
        teambit
      &lt;/a&gt; / &lt;a href="https://github.com/teambit/envs" rel="noopener noreferrer"&gt;
        envs
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Component development environments for the Bit community
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Envs - Development environments for components&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/teambit/envs/workflows/Test%20and%20Export/badge.svg"&gt;&lt;img src="https://github.com/teambit/envs/workflows/Test%20and%20Export/badge.svg" alt="Test and Export"&gt;&lt;/a&gt;
&lt;a href="https://bit.dev/bit/envs" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6252303494ca261c5ca84c214ac8f90c0fb74ac950fa5816621c61dfb1bd651d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64796e616d69632f6a736f6e2e7376673f636f6c6f723d366533393931266c6162656c3d636f6d706f6e656e74732671756572793d7061796c6f61642e746f74616c436f6d706f6e656e74732675726c3d68747470732533412532462532466170692e6269742e64657625324673636f7065253246626974253246656e7673" alt="components"&gt;&lt;/a&gt;
&lt;a href="https://opensource.org/licenses/Apache-2.0" rel="nofollow noopener noreferrer"&gt;&lt;img alt="apache" src="https://camo.githubusercontent.com/a549a7a30bacba7bfceebdc207a8e86c3f2c02995a2527640dca30048fd2b64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d417061636865253230322e302d626c75652e737667"&gt;&lt;/a&gt;
&lt;a href="https://github.com/prettier/prettier" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7c31269a4fab27bd4b327813e7a459cf7a76da0b0b009254bf949a20889d2b6c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374796c65645f776974682d70726574746965722d6666363962342e737667" alt="styled with prettier"&gt;&lt;/a&gt;
&lt;a href="https://join.slack.com/t/bit-dev-community/shared_invite/enQtNzM2NzQ3MTQzMTg3LWI2YmFmZjQwMTkxNmFmNTVkYzU2MGI2YjgwMmJlZDdkNWVhOGIzZDFlYjg4MGRmOTM4ODAxNTIxMTMwNWVhMzg" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f9fee80bdd352b907b4a65da28edcb67009656b1876d75bbf687bd9b40990094/68747470733a2f2f62616467656e2e6e6f772e73682f62616467652f636861742f6f6e253230536c61636b2f6379616e" alt="Slack"&gt;&lt;/a&gt;
&lt;a href="https://www.reddit.com/r/bit_dev/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/80e75912f3b415452f7706e9784bd096f6bebad82f186bd3e52adec114139d88/68747470733a2f2f62616467656e2e6e6f772e73682f62616467652f636861742f6f6e2532305265646469742f6f72616e6765" alt="reddit"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A curated list of &lt;strong&gt;Extensions&lt;/strong&gt; maintained by Bit's &lt;a href="https://github.com/orgs/teambit/people" rel="noopener noreferrer"&gt;maintainers&lt;/a&gt; to use as dev tools for components. These extensions implement best practices for distributing components and setting them up to be reused across projects.&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://bit.dev/bit/envs" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d88d1645312dc64f7835e9c34803007fd2cf2f0c3a54cafa2df39ddc419ce7f1/68747470733a2f2f73746f726167652e676f6f676c65617069732e636f6d2f6269742d646f63732f53637265656e25323053686f74253230323031392d30362d30362532306174253230312e32362e3332253230504d2e706e67"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick links&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://bit.dev/bit/envs" rel="nofollow noopener noreferrer"&gt;Browse Envs&lt;/a&gt; • &lt;a href="https://docs.bit.dev/docs/building-components.html" rel="nofollow noopener noreferrer"&gt;Implementing Envs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bit.dev/bit/envs" rel="nofollow noopener noreferrer"&gt;Compiler/Tester collection&lt;/a&gt; • &lt;a href="https://docs.bit.dev/docs/building-components.html" rel="nofollow noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Which compiler to use?&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;Flavor&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Env&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Import Command&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;React JS&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/compilers/react" rel="nofollow noopener noreferrer"&gt;react&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/compilers/react -c&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;React TS&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/compilers/react-typescript" rel="nofollow noopener noreferrer"&gt;react-typescript&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/compilers/react-typescript -c&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;React Native JS&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/compilers/react-native" rel="nofollow noopener noreferrer"&gt;react-native&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/compilers/react-native -c&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;React Native TS&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/compilers/react-native-typescript" rel="nofollow noopener noreferrer"&gt;react-native-typescript&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/compilers/react-native-typescript -c&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;Vue&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/bundlers/vue" rel="nofollow noopener noreferrer"&gt;vue&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/bundlers/vue -c&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;Angular&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/compilers/angular" rel="nofollow noopener noreferrer"&gt;angular&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/compilers/angular -c&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;Typescript Vanilla&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/compilers/typescript" rel="nofollow noopener noreferrer"&gt;typescript&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/compilers/typescript -c&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;Javascript Vanilla&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/compilers/babel" rel="nofollow noopener noreferrer"&gt;babel&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/compilers/babel -c&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;Stencil&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/compilers/stencil" rel="nofollow noopener noreferrer"&gt;stencil&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/compilers/stencil -c&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Which tester to use?&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;Flavor&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Env&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Import Command&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;Mocha&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://bit.dev/bit/envs/testers/mocha" rel="nofollow noopener noreferrer"&gt;mocha&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;bit import bit.envs/testers/mocha -t&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is Bit?&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Bit makes it easy to share and manage components between projects and&lt;/strong&gt;…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/teambit/envs" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>reactnative</category>
    </item>
    <item>
      <title>How to comma-separate your number in JavaScript</title>
      <dc:creator>Josh Kuttler</dc:creator>
      <pubDate>Thu, 19 Dec 2019 10:56:15 +0000</pubDate>
      <link>https://forem.com/joshk2/how-to-comma-separate-your-number-in-javascript-38oo</link>
      <guid>https://forem.com/joshk2/how-to-comma-separate-your-number-in-javascript-38oo</guid>
      <description>&lt;p&gt;I created a simple function that does the trick with a regex expression. &lt;/p&gt;

&lt;p&gt;The function receives either a string or a number and returns the formatted number with correct commas:&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="nf"&gt;formatNumber&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(\d)(?=(\d\d\d)&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(?!\d))&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$1,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wrote this function in &lt;a href="https://bit.dev/joshk/jotils/format-number" rel="noopener noreferrer"&gt;TypeScript and added tests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've exported it to &lt;a href="https://bit.dev/" rel="noopener noreferrer"&gt;bit.dev&lt;/a&gt; with a live demo and docs.&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%2F51qgeacthbkozv0eh0nn.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%2F51qgeacthbkozv0eh0nn.png" alt="Alt Text" width="800" height="322"&gt;&lt;/a&gt;&lt;br&gt;
Also, it can be easily consumed with NPM/Yarn/Bit. &lt;br&gt;
&lt;a href="https://bit.dev/joshk/jotils/format-number" rel="noopener noreferrer"&gt;https://bit.dev/joshk/jotils/format-number&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have a better way to write this function, please write a comment.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>functional</category>
    </item>
    <item>
      <title>Build a Tic Tac Toe App with TypeScript, React and Mocha</title>
      <dc:creator>Josh Kuttler</dc:creator>
      <pubDate>Tue, 10 Sep 2019 21:16:08 +0000</pubDate>
      <link>https://forem.com/joshk2/build-a-tic-tac-toe-app-with-typescript-react-and-mocha-2n1</link>
      <guid>https://forem.com/joshk2/build-a-tic-tac-toe-app-with-typescript-react-and-mocha-2n1</guid>
      <description>&lt;p&gt;Learn how to compose a tic-tac-toe app with React and TypeScript 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%2Fab1z5zprjibjwdlj1bkr.jpeg" 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%2Fab1z5zprjibjwdlj1bkr.jpeg" width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simple Tic-Tac-Toe game built with modularity in mind and &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="noopener noreferrer"&gt;shared on Bit&lt;/a&gt;. After sharing, my game’s components can be tweaked and tested on Bit’s live PlayGround. &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="noopener noreferrer"&gt;Go to my components collection&lt;/a&gt; on Bit to test or consume the entire game or just some of its components, using NPM, Yarn or Bit.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/JoshK2" rel="noopener noreferrer"&gt;
        JoshK2
      &lt;/a&gt; / &lt;a href="https://github.com/JoshK2/tic-tac-toe-game-using-bit" rel="noopener noreferrer"&gt;
        tic-tac-toe-game-using-bit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Simple Tic Tac Toe game built with react-typescript components
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Modular Tic Tac Toe Game built with TypeScript and tested with Mocha &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ba716c2cf009913b03429b8f03f81ec54d581640a454e9733dbe85e16e2e7f70/68747470733a2f2f696d672e736869656c64732e696f2f6269742f636f6c6c656374696f6e2f746f74616c2d636f6d706f6e656e74732f6a6f73686b2f7469632d7461632d746f652d67616d652e737667" alt="components"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A simple Tic Tac Toe game build with TypeScript components and test with Mocha tester then shared them to &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="nofollow noopener noreferrer"&gt;bit&lt;/a&gt; for testing in the live PlayGround and see the result of tests runnig in bit.&lt;br&gt;
Allow users to consume the entire game or just a part of the game components using NPM and Yarn or using bit to consume and modify the component directly inside the project.&lt;/p&gt;
&lt;p&gt;The game has multiple options to modify the game rules, like the dynamic dimension of the table, and the number of matching value to win the game.&lt;/p&gt;
&lt;p&gt;Try the game in live PlayGround in the project &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="nofollow noopener noreferrer"&gt;collection&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9a61ea3c35bdd04f1fa9551ca142258d86ba7f280d2e7d8c62534afd45d4b1d6/68747470733a2f2f692e696d6167657375702e636f2f696d61676573322f353234653062353563363765623561653861306361313561373664353464663939333061353063392e6a7067"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tutorial&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;See the full tutorial- build your own modular application with React TypeScript components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.bitsrc.io/build-a-tic-tac-toe-game-with-typescript-react-and-mocha-ce6f1e74c996" rel="nofollow noopener noreferrer"&gt;Build a Tic Tac Toe App with TypeScript, React and Mocha&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Import and use the entire game component in&lt;/h2&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/JoshK2/tic-tac-toe-game-using-bit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;When building a game like Tic-Tac-Toe “with modularity in mind”, it's hard to think of a reason for the UI components to be reused ever again, so I kept my focus primarily on the game’s utility functions.&lt;/p&gt;

&lt;p&gt;I chose TypeScript as my coding language of choice — compiled by &lt;a href="https://bit.dev/bit/envs/compilers/react-typescript" rel="noopener noreferrer"&gt;Bit’s TypeScript compiler&lt;/a&gt; and used Mocha for testing.&lt;/p&gt;

&lt;p&gt;To install components from my project, first configure &lt;a href="https://bit.dev" rel="noopener noreferrer"&gt;bit.dev&lt;/a&gt; as a scoped registry (copy and paste to your terminal) — this is done only once! later uses of bit do not require you to configure again.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm config set '@bit:registry' [https://node.bit.dev](https://node.bit.dev)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;and then install the component using Yarn or NPM:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i [@bit/joshk](http://twitter.com/bit/joshk).tic-tac-toe-game.game
yarn add [@bit/joshk](http://twitter.com/bit/joshk).tic-tac-toe-game.game
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Game Component
&lt;/h2&gt;

&lt;p&gt;The ‘game’ component is my app’s main component — composed using one component from ‘Board’ and two components from ‘&lt;a href="https://bit.dev/primefaces/primereact" rel="noopener noreferrer"&gt;Prime React&lt;/a&gt;’.&lt;/p&gt;

&lt;p&gt;I used the &lt;a href="https://bit.dev/primefaces/primereact/button" rel="noopener noreferrer"&gt;button&lt;/a&gt; and the &lt;a href="https://bit.dev/primefaces/primereact/inputtext" rel="noopener noreferrer"&gt;input-text&lt;/a&gt; for the configuration screen — test and see the code &lt;a href="https://bit.dev/joshk/tic-tac-toe-game/game/~code#Game/Game.tsx" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Install PrimeReact components in your project:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @bit/primefaces.primereact.inputtext
yarn add @bit/primefaces.primereact.button
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;After setting the parameters, you can click ‘Play’ and… Play!&lt;/p&gt;
&lt;h2&gt;
  
  
  Board Component
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://bit.dev/joshk/tic-tac-toe-game/board" rel="noopener noreferrer"&gt;board&lt;/a&gt; component creates a dynamic table by props, manage player turn and check for the winner. Test and see the code &lt;a href="https://bit.dev/joshk/tic-tac-toe-game/board/~code#Board/Board.tsx" rel="noopener noreferrer"&gt;here&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%2Feaohr4cvyidxycdfdgnh.jpeg" 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%2Feaohr4cvyidxycdfdgnh.jpeg" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Square Component
&lt;/h2&gt;

&lt;p&gt;The square component is a simple cell that receives value with optional color and sends an event to the board component when the value changes. Test and see the code &lt;a href="https://bit.dev/joshk/tic-tac-toe-game/square/~code#Square.tsx" rel="noopener noreferrer"&gt;here&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%2F7zxo3fobq27xrldysiis.jpeg" 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%2F7zxo3fobq27xrldysiis.jpeg" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Empty cell function
&lt;/h2&gt;

&lt;p&gt;‘Empty cell function’ Is a helper &lt;a href="https://bit.dev/joshk/tic-tac-toe-game/utils/have-empty-cell" rel="noopener noreferrer"&gt;function&lt;/a&gt; to &lt;a href="https://bit.dev/joshk/tic-tac-toe-game/utils/winner-calc" rel="noopener noreferrer"&gt;winner-calc function&lt;/a&gt; that checks if there are any empty cells in the game’s table.&lt;/p&gt;

&lt;p&gt;Bit lets you see the docs for the component and the results of the tests:&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%2Fi6sc70mkxxji77ixl1e2.jpeg" 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%2Fi6sc70mkxxji77ixl1e2.jpeg" width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code of the function:&lt;/p&gt;


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



&lt;h2&gt;
  
  
  Winner Calculation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://bit.dev/joshk/tic-tac-toe-game/utils/winner-calc" rel="noopener noreferrer"&gt;Winner calculation&lt;/a&gt; is a function that checks for the winner in horizontal, vertical and diagonal cases.&lt;/p&gt;

&lt;p&gt;Bit let you see the docs for the component and the results of the tests:&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%2F5t4jqr8cqm0iutu91a7s.jpeg" 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%2F5t4jqr8cqm0iutu91a7s.jpeg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code for the function:&lt;/p&gt;


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


&lt;p&gt;The project is available in my &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="noopener noreferrer"&gt;bit collection&lt;/a&gt; and in my GitHub repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/JoshK2" rel="noopener noreferrer"&gt;
        JoshK2
      &lt;/a&gt; / &lt;a href="https://github.com/JoshK2/tic-tac-toe-game-using-bit" rel="noopener noreferrer"&gt;
        tic-tac-toe-game-using-bit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Simple Tic Tac Toe game built with react-typescript components
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Modular Tic Tac Toe Game built with TypeScript and tested with Mocha &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ba716c2cf009913b03429b8f03f81ec54d581640a454e9733dbe85e16e2e7f70/68747470733a2f2f696d672e736869656c64732e696f2f6269742f636f6c6c656374696f6e2f746f74616c2d636f6d706f6e656e74732f6a6f73686b2f7469632d7461632d746f652d67616d652e737667" alt="components"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A simple Tic Tac Toe game build with TypeScript components and test with Mocha tester then shared them to &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="nofollow noopener noreferrer"&gt;bit&lt;/a&gt; for testing in the live PlayGround and see the result of tests runnig in bit.&lt;br&gt;
Allow users to consume the entire game or just a part of the game components using NPM and Yarn or using bit to consume and modify the component directly inside the project.&lt;/p&gt;
&lt;p&gt;The game has multiple options to modify the game rules, like the dynamic dimension of the table, and the number of matching value to win the game.&lt;/p&gt;
&lt;p&gt;Try the game in live PlayGround in the project &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="nofollow noopener noreferrer"&gt;collection&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://bit.dev/joshk/tic-tac-toe-game" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9a61ea3c35bdd04f1fa9551ca142258d86ba7f280d2e7d8c62534afd45d4b1d6/68747470733a2f2f692e696d6167657375702e636f2f696d61676573322f353234653062353563363765623561653861306361313561373664353464663939333061353063392e6a7067"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tutorial&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;See the full tutorial- build your own modular application with React TypeScript components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.bitsrc.io/build-a-tic-tac-toe-game-with-typescript-react-and-mocha-ce6f1e74c996" rel="nofollow noopener noreferrer"&gt;Build a Tic Tac Toe App with TypeScript, React and Mocha&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Import and use the entire game component in&lt;/h2&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/JoshK2/tic-tac-toe-game-using-bit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Feel free to comment below and follow me on &lt;a href="https://twitter.com/JoshKuttler" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; 😃&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>How to Build a Super-Modular Todo App with React and Bit Components</title>
      <dc:creator>Josh Kuttler</dc:creator>
      <pubDate>Thu, 05 Sep 2019 16:37:54 +0000</pubDate>
      <link>https://forem.com/joshk2/how-to-build-a-super-modular-todo-app-with-react-and-bit-components-18j9</link>
      <guid>https://forem.com/joshk2/how-to-build-a-super-modular-todo-app-with-react-and-bit-components-18j9</guid>
      <description>&lt;p&gt;How to compose a highly modular React application with reusable components from 5 different libraries.&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%2F889cidi9xxl0tsulqk65.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%2F889cidi9xxl0tsulqk65.png" alt="The final todo app composition with Bit" width="800" height="298"&gt;&lt;/a&gt;&lt;em&gt;The final todo app composition with Bit&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Modular programming has been around since the 60s, and the term itself was set at 1968 by &lt;a href="https://en.wikipedia.org/wiki/Larry_Constantine" rel="noopener noreferrer"&gt;Larry Constantine&lt;/a&gt; and extended ever since.&lt;/p&gt;

&lt;p&gt;Today, in the technological world of component-based libraries like &lt;a href="https://github.com/facebook/react" rel="noopener noreferrer"&gt;React&lt;/a&gt; and with tools like &lt;a href="https://github.com/teambit/bit" rel="noopener noreferrer"&gt;Bit&lt;/a&gt;, application modularity can be taken to a whole new level.&lt;/p&gt;

&lt;p&gt;We will compose a simple React Todo application using reusable components from 5 popular libraries like &lt;a href="https://bit.dev/mui-org/material-ui" rel="noopener noreferrer"&gt;Material-UI&lt;/a&gt;, &lt;a href="https://bit.dev/grommet/grommet" rel="noopener noreferrer"&gt;Grommet&lt;/a&gt; and &lt;a href="https://bit.dev/semantic-org/semantic-ui-react" rel="noopener noreferrer"&gt;Semantic-UI&lt;/a&gt;. Thanks to Bit, we can quickly isolate and compose these components into an app.&lt;/p&gt;

&lt;p&gt;When done, not only we will compose a highly-modular app from reusable components, but we will have a collection of components we can reuse to build more apps. The entire app is shared as a reusable component, which can be extended and composed with other components to build larger apps.&lt;/p&gt;

&lt;p&gt;This is very exciting, as it’s a live implementation of full-blown modular application composition with a Lego-like experience.&lt;/p&gt;

&lt;p&gt;This is the result of the todo list app:&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%2Fm6lo7cwrzwjy1vwaugti.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%2Fm6lo7cwrzwjy1vwaugti.png" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here’s the app’s GitHub repo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/JoshK2" rel="noopener noreferrer"&gt;
        JoshK2
      &lt;/a&gt; / &lt;a href="https://github.com/JoshK2/basic-todo-app-using-bit" rel="noopener noreferrer"&gt;
        basic-todo-app-using-bit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A highly-modular React todo application composed of reusable components from 5 different collections. Full-blown software modularity.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Highly-modular React Todo application built of reusable Bit components &lt;a href="https://bit.dev/joshk/basic-todo-app" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d2938954e045839c0c50b9ea9ec79b8d98c68030df54136eec6621021bb47ada/68747470733a2f2f696d672e736869656c64732e696f2f6269742f636f6c6c656374696f6e2f746f74616c2d636f6d706f6e656e74732f6a6f73686b2f62617369632d746f646f2d6170702e737667" alt="components"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A basic React todo aplication composed of &lt;a href="https://bit.dev" rel="nofollow noopener noreferrer"&gt;bit&lt;/a&gt; componnets shared from 5 different popular React UI libraries inlcuding &lt;a href="https://github.com/grommet/grommet" rel="noopener noreferrer"&gt;Grommet&lt;/a&gt;, &lt;a href="https://github.com/Semantic-Org/Semantic-UI-React" rel="noopener noreferrer"&gt;Semantic-UI React&lt;/a&gt;, &lt;a href="https://github.com/primefaces/primereact" rel="noopener noreferrer"&gt;Primereact&lt;/a&gt; and &lt;a href="https://github.com/lodash/lodash" rel="noopener noreferrer"&gt;Lodash&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All the reusable components used to build this app are &lt;a href="https://bit.dev/joshk/basic-todo-app" rel="nofollow noopener noreferrer"&gt;availabe in this collection&lt;/a&gt;
The final todo application is also &lt;a href="https://bit.dev/joshk/basic-todo-app/todo-app" rel="nofollow noopener noreferrer"&gt;available as a reusbale bit component&lt;/a&gt;, which can be extended and composed with other components to build larger applications.&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://bit.dev/joshk/basic-todo-app" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8d02c9a9809c13d4084c775b444b45c6fbbe4db61bdc8e47ae352bac6a51f5ca/68747470733a2f2f692e696d6167657375702e636f2f696d61676573322f663262356363396139313866613538656432313036353730656435623464626232303834366237662e706e67"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Motivation&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Demonstrating software modularity in the age of components with React and Bit.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tutorial&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;See the full tutorial- build your own modular application with reusable components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.bitsrc.io/build-a-super-modular-todo-app-with-react-and-bit-components-aa06bbac4084" rel="nofollow noopener noreferrer"&gt;Build a Super Modular Todo App with React and Bit Components&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Wich components I used?&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Semantic UI React&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://bit.dev/semantic-org/semantic-ui-react/list" rel="nofollow noopener noreferrer"&gt;semantic-ui-react list component&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.dev/semantic-org/semantic-ui-react/icon" rel="nofollow noopener noreferrer"&gt;semantic-ui-react icon component&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.dev/semantic-org/semantic-ui-react/internal/style-links" rel="nofollow noopener noreferrer"&gt;semantic-ui-react css link component&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;PrimeReact&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://bit.dev/primefaces/primereact/inputtextarea" rel="nofollow noopener noreferrer"&gt;primereact inputtextarea component&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.dev/primefaces/primereact/button" rel="nofollow noopener noreferrer"&gt;primereact button component&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.dev/primefaces/primereact/internal/stylelinks" rel="nofollow noopener noreferrer"&gt;primereact css link component&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Grommet&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://bit.dev/grommet/grommet/button" rel="nofollow noopener noreferrer"&gt;grommet button component&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;grommet-icons&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://bit.dev/grommet/grommet-icons/add" rel="nofollow noopener noreferrer"&gt;grommet-icons add&lt;/a&gt;…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/JoshK2/basic-todo-app-using-bit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  3 Components
&lt;/h2&gt;

&lt;p&gt;For creating the app I decided to divide the App’s code into 3 components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://bit.dev/joshk/basic-todo-app/todo-item" rel="noopener noreferrer"&gt;TodoItem component&lt;/a&gt;, text with remove option.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://bit.dev/joshk/basic-todo-app/add-item" rel="noopener noreferrer"&gt;AddItem component&lt;/a&gt;, input text area with add button and remove all button.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://bit.dev/joshk/basic-todo-app/todo-app" rel="noopener noreferrer"&gt;TodoApp component&lt;/a&gt;, this is the main code of the app that includes the TodoItem and the AddItem, so there will be a List with simple code to manage all the components options like remove, remove all and add.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Components 1+2 are modularly composed of components isolated and shared from different libraries- using &lt;a href="https://github.com/teambit/bit" rel="noopener noreferrer"&gt;Bit&lt;/a&gt; which helps us isolate, share and manage reusable components to build modular applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  TodoItem
&lt;/h2&gt;

&lt;p&gt;This component receives a simple text and id for removing the right todo item from the main list as props, and uses a &lt;a href="https://bit.dev/semantic-org/semantic-ui-react/icon?example=5c920bc8c634f0001a931747" rel="noopener noreferrer"&gt;remove icon&lt;/a&gt; from the &lt;a href="https://bit.dev/semantic-org/semantic-ui-react" rel="noopener noreferrer"&gt;semantic-ui-react&lt;/a&gt; component collection.&lt;/p&gt;

&lt;p&gt;To install the component, firsy configure &lt;a href="https://bit.dev" rel="noopener noreferrer"&gt;bit.dev&lt;/a&gt; as a scoped registry (one time action) and then install the component using Yarn:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm config set '@bit:registry' [https://node.bit.dev](https://node.bit.dev)

yarn add @bit/semantic-org.semantic-ui-react.icon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This is the code of the component, after adding some helping-code to show the remove icon and send remove as an event to the main component when remove is clicked.&lt;/p&gt;


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



&lt;p&gt;Here’s the final TodoItem component with live editing and playground in &lt;a href="https://bit.dev/joshk/basic-todo-app/todo-item" rel="noopener noreferrer"&gt;Bit&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  AddItem
&lt;/h2&gt;

&lt;p&gt;This component shows an input text area with auto resize and two buttons, one to add an item to the list, and the second to remove all items from the list. The remove all button work with props to show or hide this button.&lt;/p&gt;

&lt;p&gt;So for this, I use input text area and button from &lt;a href="https://bit.dev/primefaces/primereact" rel="noopener noreferrer"&gt;primereact&lt;/a&gt;, a button from &lt;a href="https://bit.dev/grommet/grommet" rel="noopener noreferrer"&gt;grommet&lt;/a&gt;, and icon from &lt;a href="https://bit.dev/grommet/grommet-icons" rel="noopener noreferrer"&gt;grommet-icons&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Install it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @bit/primefaces.primereact.inputtextarea
yarn add @bit/primefaces.primereact.button
yarn add @bit/primefaces.primereact.internal.stylelinks
yarn add @bit/grommet.grommet.button
yarn add @bit/grommet.grommet-icons.add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This is the code of the component after adding some helping code to use the Add button and the Remove All button.&lt;/p&gt;


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



&lt;p&gt;AddItem component with live editing and playground in &lt;a href="https://bit.dev/joshk/basic-todo-app/add-item" rel="noopener noreferrer"&gt;Bit&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  TodoApp
&lt;/h2&gt;

&lt;p&gt;This component is the main component that uses the TodoItem and the AddItem components. The component has a list of item and allow to send an initial list as a prop, and receives all the event from the other components to manage the list. Like the add item, the remove item and the remove all item.&lt;/p&gt;

&lt;p&gt;So I use List component from semantic-ui-react, and a unique id function from &lt;a href="https://bit.dev/lodash/lodash" rel="noopener noreferrer"&gt;lodash&lt;/a&gt; to avoid key error in map function.&lt;/p&gt;

&lt;p&gt;Install it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @bit/semantic-org.semantic-ui-react.list
yarn add @bit/semantic-org.semantic-ui-react.internal.style-links
yarn add @bit/lodash.lodash.unique-id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This is the main code of the app, it receives and manages all the events that come from AddItem and TodoItem components.&lt;/p&gt;


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



&lt;p&gt;Then all that’s left is to &lt;a href="https://bit.dev" rel="noopener noreferrer"&gt;export the components with Bit&lt;/a&gt;- and the final TodoApp is now a modular and reusable component, check out the live &lt;a href="https://bit.dev/joshk/basic-todo-app/todo-app" rel="noopener noreferrer"&gt;demo&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;All the reusable components we built are available in this &lt;a href="https://bit.dev/joshk/basic-todo-app" rel="noopener noreferrer"&gt;collection&lt;/a&gt;, including the final todo app&lt;/p&gt;

&lt;p&gt;Check the GitHub repo to see all the project’s code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/JoshK2" rel="noopener noreferrer"&gt;
        JoshK2
      &lt;/a&gt; / &lt;a href="https://github.com/JoshK2/basic-todo-app-using-bit" rel="noopener noreferrer"&gt;
        basic-todo-app-using-bit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A highly-modular React todo application composed of reusable components from 5 different collections. Full-blown software modularity.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Highly-modular React Todo application built of reusable Bit components &lt;a href="https://bit.dev/joshk/basic-todo-app" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d2938954e045839c0c50b9ea9ec79b8d98c68030df54136eec6621021bb47ada/68747470733a2f2f696d672e736869656c64732e696f2f6269742f636f6c6c656374696f6e2f746f74616c2d636f6d706f6e656e74732f6a6f73686b2f62617369632d746f646f2d6170702e737667" alt="components"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A basic React todo aplication composed of &lt;a href="https://bit.dev" rel="nofollow noopener noreferrer"&gt;bit&lt;/a&gt; componnets shared from 5 different popular React UI libraries inlcuding &lt;a href="https://github.com/grommet/grommet" rel="noopener noreferrer"&gt;Grommet&lt;/a&gt;, &lt;a href="https://github.com/Semantic-Org/Semantic-UI-React" rel="noopener noreferrer"&gt;Semantic-UI React&lt;/a&gt;, &lt;a href="https://github.com/primefaces/primereact" rel="noopener noreferrer"&gt;Primereact&lt;/a&gt; and &lt;a href="https://github.com/lodash/lodash" rel="noopener noreferrer"&gt;Lodash&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All the reusable components used to build this app are &lt;a href="https://bit.dev/joshk/basic-todo-app" rel="nofollow noopener noreferrer"&gt;availabe in this collection&lt;/a&gt;
The final todo application is also &lt;a href="https://bit.dev/joshk/basic-todo-app/todo-app" rel="nofollow noopener noreferrer"&gt;available as a reusbale bit component&lt;/a&gt;, which can be extended and composed with other components to build larger applications.&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://bit.dev/joshk/basic-todo-app" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8d02c9a9809c13d4084c775b444b45c6fbbe4db61bdc8e47ae352bac6a51f5ca/68747470733a2f2f692e696d6167657375702e636f2f696d61676573322f663262356363396139313866613538656432313036353730656435623464626232303834366237662e706e67"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Motivation&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Demonstrating software modularity in the age of components with React and Bit.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tutorial&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;See the full tutorial- build your own modular application with reusable components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.bitsrc.io/build-a-super-modular-todo-app-with-react-and-bit-components-aa06bbac4084" rel="nofollow noopener noreferrer"&gt;Build a Super Modular Todo App with React and Bit Components&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Wich components I used?&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Semantic UI React&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://bit.dev/semantic-org/semantic-ui-react/list" rel="nofollow noopener noreferrer"&gt;semantic-ui-react list component&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.dev/semantic-org/semantic-ui-react/icon" rel="nofollow noopener noreferrer"&gt;semantic-ui-react icon component&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.dev/semantic-org/semantic-ui-react/internal/style-links" rel="nofollow noopener noreferrer"&gt;semantic-ui-react css link component&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;PrimeReact&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://bit.dev/primefaces/primereact/inputtextarea" rel="nofollow noopener noreferrer"&gt;primereact inputtextarea component&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.dev/primefaces/primereact/button" rel="nofollow noopener noreferrer"&gt;primereact button component&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.dev/primefaces/primereact/internal/stylelinks" rel="nofollow noopener noreferrer"&gt;primereact css link component&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Grommet&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://bit.dev/grommet/grommet/button" rel="nofollow noopener noreferrer"&gt;grommet button component&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;grommet-icons&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://bit.dev/grommet/grommet-icons/add" rel="nofollow noopener noreferrer"&gt;grommet-icons add&lt;/a&gt;…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/JoshK2/basic-todo-app-using-bit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;In this post, we’ve seen a very real example of modular software composition with reusable React components and Bit.&lt;/p&gt;

&lt;p&gt;When we base our software design on modularity of &lt;a href="https://addyosmani.com/first/" rel="noopener noreferrer"&gt;smaller focused components&lt;/a&gt;, we build a better application which is easier to develop, maintain, test and extend. Today, building modular apps becomes more practical- and more fun- than ever before in history.&lt;/p&gt;

&lt;p&gt;The same can be done not only with React and not only with frontEnd components. In my next posts, I’ll play with a modular composition for a verity of different technologies and architectures. Thanks for reading and feel free to ask anything! Cheers 🚀&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How I Created My Own React Spinners Library</title>
      <dc:creator>Josh Kuttler</dc:creator>
      <pubDate>Tue, 03 Sep 2019 16:00:02 +0000</pubDate>
      <link>https://forem.com/joshk2/how-i-created-my-own-react-spinners-library-4ckn</link>
      <guid>https://forem.com/joshk2/how-i-created-my-own-react-spinners-library-4ckn</guid>
      <description>&lt;p&gt;I’ve created an application that uses Airtable as a database. I’ve used a spinner to take the place of a dull blank page which would otherwise be presented to the user in the time that it takes for the requested data to arrive and for the page to get rendered accordingly.&lt;/p&gt;

&lt;p&gt;I could have used an existing react spinners library, but instead, I decided to use this chance to learn how to build my own spinners and my own React component library. So, in this post, I’ll show you my library, and an example of how to use a spinner.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://bit.dev/joshk/react-spinners-css" rel="noopener noreferrer"&gt;React Spinners Library&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;So, without further ado, here’s my react spinners library (&lt;a href="https://github.com/JoshK2/react-spinners-css" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, &lt;a href="https://bit.dev/joshk/react-spinners-css" rel="noopener noreferrer"&gt;Bit&lt;/a&gt;). It’s based on loading.io CSS loaders. I’ve added the option to send color and size as props of the component so that it’s easier to customize the spinners. I’ve exported the spinners (twelve in total) to &lt;a href="https://bit.dev/joshk/react-spinners-css" rel="noopener noreferrer"&gt;bit.dev&lt;/a&gt; so you may easily view and tweak them in Bit’s live playground, and install them as packages with NPM or Yarn (or get their source code using Bit import).&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/JoshK2" rel="noopener noreferrer"&gt;
        JoshK2
      &lt;/a&gt; / &lt;a href="https://github.com/JoshK2/react-spinners-css" rel="noopener noreferrer"&gt;
        react-spinners-css
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Amazing collection of React spinners components with pure css
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;React Spinners CSS Loaders (&lt;a href="https://github.com/JoshK2/vue-spinners-css" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;, &lt;a href="https://github.com/JoshK2/ng-spinners" rel="noopener noreferrer"&gt;Angular&lt;/a&gt;, &lt;a href="https://github.com/ayodejii/blazor-spinner-css" rel="noopener noreferrer"&gt;Blazor&lt;/a&gt;)&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fdeeb9dd1b673943f35c00ac8919da4170dcc4f9c7864497cfe403d7be84855e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6269745f636f6d706f6e656e74732d31342d366533393931" alt="bit components"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9a1611dcbba93c7e9d0cd3d383a4107bc2aeb44f2cd93707033376bf1f3f4ff2/68747470733a2f2f62616467652e667572792e696f2f6a732f72656163742d7370696e6e6572732d6373732e737667" alt="npm version"&gt;&lt;/a&gt;
&lt;a href="https://github.com/JoshK2/react-spinners-css/stargazers" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cfe12f70c4d856210829a9948df3b3c4599a71b5bd5f3e96f14404f32401ce2e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f6a6f73686b322f72656163742d7370696e6e6572732d637373" alt="GitHub stars"&gt;&lt;/a&gt;
&lt;a href="https://raw.githubusercontent.com/JoshK2/react-spinners-css/master/LICENSE" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667" alt="GitHub license"&gt;&lt;/a&gt;
&lt;a href="https://twitter.com/JoshKuttler" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1496ce1365d65e94ad5e350aad89dfd0528de57cdef7b4a103e83b36aafa85ae/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f666f6c6c6f772f6a6f73686b7574746c6572" alt="Twitter Follow"&gt;&lt;/a&gt;
&lt;a href="https://libs.tech/project/205101803/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/da73a42a2fb85413905f2343a5263367ed514034b9dbfb0e168d979ac21942f7/68747470733a2f2f6c6962732e746563682f70726f6a6563742f3230353130313830332f62616467652e737667" alt="libs.tech recommends"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b72a322503d7a7a68c5c7669bd3d5db9b2ca9dba29931aa5418a1b711f1cd3b4/68747470733a2f2f692e696d6167657375702e636f2f696d61676573322f316436376261616666306261393834393739323334643935323731303939383433323939646461312e676966"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Amazing collection of React spinners components with pure css.&lt;br&gt;
The React spinners are based on loading.io and from all over the web.&lt;br&gt;
If you want to add your own spinner, please follow the &lt;a href="https://github.com/JoshK2/react-spinners-css/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contributing guidelines&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;💅 No extra CSS imports&lt;/li&gt;
&lt;li&gt;✂️ Zero dependencies&lt;/li&gt;
&lt;li&gt;📦 Spinners can be installing separately&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;&lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Browse components and explore their props with &lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;Bit&lt;/a&gt;.&lt;br&gt;
Install specific react spinner component with npm, yarn or bit without having to install the whole project.&lt;br&gt;
&lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;Install components and live demo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img width="200" height="39" src="https://camo.githubusercontent.com/ef967254c06c1f779992a9e220223c8296b7562124a6427a9c3089d951fea4d9/68747470733a2f2f692e696d6167657375702e636f2f696d61676573322f346136346630303839353163643636653536643466316530313431613237646635383461316539342e706e67" class="js-gh-image-fallback"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 List of Spinners&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Each component accepts a &lt;code&gt;color&lt;/code&gt; prop, and few accepts also &lt;code&gt;size&lt;/code&gt; prop.&lt;br&gt;
The default &lt;code&gt;color&lt;/code&gt; prop is &lt;code&gt;#7f58af&lt;/code&gt;.&lt;br&gt;
Component that accepts &lt;code&gt;size&lt;/code&gt; prop have a default size in pixel.&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Spinner&lt;/th&gt;
&lt;th&gt;color: string&lt;/th&gt;
&lt;th&gt;size: number&lt;/th&gt;
&lt;th&gt;className: string&lt;/th&gt;
&lt;th&gt;style: object&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;Circle/&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#7f58af&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;Default/&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#7f58af&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;80&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;Ellipsis/&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#7f58af&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;80&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/JoshK2/react-spinners-css" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;For example, this is the circle loader and the component can receive color and size props:&lt;/p&gt;


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


&lt;p&gt;and the code import a very simple CSS code, exactly the same from loading.io CSS loader:&lt;/p&gt;


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


&lt;h2&gt;
  
  
  How to use Loader animation in your React.js application?
&lt;/h2&gt;

&lt;p&gt;So, you have a component that sends a request and stores the received data in an array inside your state object. The obvious thing to do is check if the array is empty and if so, display the spinner.&lt;/p&gt;

&lt;p&gt;For this example, I used a &lt;a href="https://bit.dev/joshk/react-spinners-css/facebook" rel="noopener noreferrer"&gt;Facebook spinner&lt;/a&gt; with a very simple page that waiting 5 seconds until to show a list of cars.&lt;/p&gt;


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


&lt;p&gt;It’s very simple to use and allows you to show a nice animation loader until the data is loaded.&lt;/p&gt;

&lt;p&gt;Also, you can use a custom color in any spinner, just send a color inside the color property, 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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Facebook&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Facebook&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#cecece&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Or be crazy and use a random color with my &lt;a href="https://bit.dev/joshk/jotils/get-random-color" rel="noopener noreferrer"&gt;random color generator component&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Facebook&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;getRandomColor&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can see the result with random color in this live demo &lt;a href="https://bit.dev/joshk/react-spinners-css/facebook?example=5d6bc96a93fdc2001a39ab1d" rel="noopener noreferrer"&gt;facebook react spinner&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to see more react spinners examples, check out my react spinners components collection in &lt;a href="https://bit.dev/joshk/react-spinners-css" rel="noopener noreferrer"&gt;bit.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For any issue or missing features, please open an issue on &lt;a href="https://github.com/JoshK2/react-spinners-css" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and I’ll do my best.&lt;/p&gt;

&lt;p&gt;And of course, if you like it, star it!&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/JoshK2" rel="noopener noreferrer"&gt;
        JoshK2
      &lt;/a&gt; / &lt;a href="https://github.com/JoshK2/react-spinners-css" rel="noopener noreferrer"&gt;
        react-spinners-css
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Amazing collection of React spinners components with pure css
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;React Spinners CSS Loaders (&lt;a href="https://github.com/JoshK2/vue-spinners-css" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;, &lt;a href="https://github.com/JoshK2/ng-spinners" rel="noopener noreferrer"&gt;Angular&lt;/a&gt;, &lt;a href="https://github.com/ayodejii/blazor-spinner-css" rel="noopener noreferrer"&gt;Blazor&lt;/a&gt;)&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fdeeb9dd1b673943f35c00ac8919da4170dcc4f9c7864497cfe403d7be84855e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6269745f636f6d706f6e656e74732d31342d366533393931" alt="bit components"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9a1611dcbba93c7e9d0cd3d383a4107bc2aeb44f2cd93707033376bf1f3f4ff2/68747470733a2f2f62616467652e667572792e696f2f6a732f72656163742d7370696e6e6572732d6373732e737667" alt="npm version"&gt;&lt;/a&gt;
&lt;a href="https://github.com/JoshK2/react-spinners-css/stargazers" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cfe12f70c4d856210829a9948df3b3c4599a71b5bd5f3e96f14404f32401ce2e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f6a6f73686b322f72656163742d7370696e6e6572732d637373" alt="GitHub stars"&gt;&lt;/a&gt;
&lt;a href="https://raw.githubusercontent.com/JoshK2/react-spinners-css/master/LICENSE" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667" alt="GitHub license"&gt;&lt;/a&gt;
&lt;a href="https://twitter.com/JoshKuttler" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1496ce1365d65e94ad5e350aad89dfd0528de57cdef7b4a103e83b36aafa85ae/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f666f6c6c6f772f6a6f73686b7574746c6572" alt="Twitter Follow"&gt;&lt;/a&gt;
&lt;a href="https://libs.tech/project/205101803/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/da73a42a2fb85413905f2343a5263367ed514034b9dbfb0e168d979ac21942f7/68747470733a2f2f6c6962732e746563682f70726f6a6563742f3230353130313830332f62616467652e737667" alt="libs.tech recommends"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b72a322503d7a7a68c5c7669bd3d5db9b2ca9dba29931aa5418a1b711f1cd3b4/68747470733a2f2f692e696d6167657375702e636f2f696d61676573322f316436376261616666306261393834393739323334643935323731303939383433323939646461312e676966"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Amazing collection of React spinners components with pure css.&lt;br&gt;
The React spinners are based on loading.io and from all over the web.&lt;br&gt;
If you want to add your own spinner, please follow the &lt;a href="https://github.com/JoshK2/react-spinners-css/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contributing guidelines&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;💅 No extra CSS imports&lt;/li&gt;
&lt;li&gt;✂️ Zero dependencies&lt;/li&gt;
&lt;li&gt;📦 Spinners can be installing separately&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;&lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Browse components and explore their props with &lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;Bit&lt;/a&gt;.&lt;br&gt;
Install specific react spinner component with npm, yarn or bit without having to install the whole project.&lt;br&gt;
&lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;Install components and live demo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bit.cloud/joshk/react-spinners-css" rel="nofollow noopener noreferrer"&gt;&lt;img width="200" height="39" src="https://camo.githubusercontent.com/ef967254c06c1f779992a9e220223c8296b7562124a6427a9c3089d951fea4d9/68747470733a2f2f692e696d6167657375702e636f2f696d61676573322f346136346630303839353163643636653536643466316530313431613237646635383461316539342e706e67" class="js-gh-image-fallback"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 List of Spinners&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Each component accepts a &lt;code&gt;color&lt;/code&gt; prop, and few accepts also &lt;code&gt;size&lt;/code&gt; prop.&lt;br&gt;
The default &lt;code&gt;color&lt;/code&gt; prop is &lt;code&gt;#7f58af&lt;/code&gt;.&lt;br&gt;
Component that accepts &lt;code&gt;size&lt;/code&gt; prop have a default size in pixel.&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Spinner&lt;/th&gt;
&lt;th&gt;color: string&lt;/th&gt;
&lt;th&gt;size: number&lt;/th&gt;
&lt;th&gt;className: string&lt;/th&gt;
&lt;th&gt;style: object&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;Circle/&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#7f58af&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;Default/&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#7f58af&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;80&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;""&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;Ellipsis/&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#7f58af&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;80&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/JoshK2/react-spinners-css" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;And follow me on &lt;a href="https://twitter.com/JoshKuttler" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; to get features updates.&lt;/p&gt;

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