<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Syakir</title>
    <description>The latest articles on DEV Community by Syakir (@syakirurahman).</description>
    <link>https://dev.to/syakirurahman</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%2F350025%2Fdeaa57e4-9e6d-48af-b514-e277d8dd00e7.jpg</url>
      <title>DEV Community: Syakir</title>
      <link>https://dev.to/syakirurahman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/syakirurahman"/>
    <language>en</language>
    <item>
      <title>checkout out my latest post :D</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Tue, 27 May 2025 13:09:01 +0000</pubDate>
      <link>https://dev.to/syakirurahman/checkout-out-my-latest-post-d-4ekj</link>
      <guid>https://dev.to/syakirurahman/checkout-out-my-latest-post-d-4ekj</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/syakirurahman/i-built-my-1st-ai-saas-its-not-as-hard-as-you-think-54id" class="crayons-story__hidden-navigation-link"&gt;I Built My 1st AI SaaS, It's Not as Hard as You Think&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/syakirurahman" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F350025%2Fdeaa57e4-9e6d-48af-b514-e277d8dd00e7.jpg" alt="syakirurahman profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/syakirurahman" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Syakir
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Syakir
                
              
              &lt;div id="story-author-preview-content-2533595" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/syakirurahman" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F350025%2Fdeaa57e4-9e6d-48af-b514-e277d8dd00e7.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Syakir&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/syakirurahman/i-built-my-1st-ai-saas-its-not-as-hard-as-you-think-54id" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 27 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/syakirurahman/i-built-my-1st-ai-saas-its-not-as-hard-as-you-think-54id" id="article-link-2533595"&gt;
          I Built My 1st AI SaaS, It's Not as Hard as You Think
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/startup"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;startup&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/syakirurahman/i-built-my-1st-ai-saas-its-not-as-hard-as-you-think-54id" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;56&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/syakirurahman/i-built-my-1st-ai-saas-its-not-as-hard-as-you-think-54id#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              16&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
      <category>startup</category>
    </item>
    <item>
      <title>I Built My 1st AI SaaS, It's Not as Hard as You Think</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Tue, 27 May 2025 13:06:44 +0000</pubDate>
      <link>https://dev.to/syakirurahman/i-built-my-1st-ai-saas-its-not-as-hard-as-you-think-54id</link>
      <guid>https://dev.to/syakirurahman/i-built-my-1st-ai-saas-its-not-as-hard-as-you-think-54id</guid>
      <description>&lt;p&gt;Hey guys 👋, Syakir here!&lt;/p&gt;

&lt;p&gt;Its been a while since my last post. I'm currently busy building app as an indiehacker. Now, i want to share about my latest project, &lt;strong&gt;&lt;a href="https://kattalog.com" rel="noopener noreferrer"&gt;Kattalog&lt;/a&gt;&lt;/strong&gt;, an AI product photography SaaS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚀 Kattalog is live on Product Hunt today — &lt;a href="https://www.producthunt.com/posts/kattalog" rel="noopener noreferrer"&gt;check it out&lt;/a&gt; and share your feedback!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This project is not the first of its kind, since there's already some similar tools out there. But i'm still building it anyway for these reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An experiment &amp;amp; learning journey to become an AI engineer &amp;amp; SaaS builder&lt;/li&gt;
&lt;li&gt;The app target market are ecommerce sellers, and I worked in Ecommerce industry for the last 5 years&lt;/li&gt;
&lt;li&gt;Based on the initial research, the market is not saturated yet&lt;/li&gt;
&lt;li&gt;The competitor apps are mostly very technical (require detailed prompts), and i try to fix this with different approach (image to image)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Built Kattalog
&lt;/h2&gt;

&lt;p&gt;The story begins about 3 months ago in the end of February 2025, when i had a chat with ChatGPT. I was chating about building another directory-site, like &lt;a href="https://alternateoss.com" rel="noopener noreferrer"&gt;AlternateOSS&lt;/a&gt;, but for AI generated images. Initially, i was going to build an AI stock photos website.&lt;/p&gt;

&lt;p&gt;I researched about it, also with ChatGPT, from the AI models to market competitions, and realize that it's not the type of product that i can build solo. Then, i ask ChatGPT to give me other ideas that fit my constraints, but still related to AI images with not-really saturated market. That's when i decide to built Kattalog, an AI product photography app.&lt;/p&gt;

&lt;p&gt;Then, i tried the existing competitors to find my app value proposition. They gave me a lot of idea, but in the end i only focus to build only core features for MVP.&lt;/p&gt;

&lt;p&gt;I started building it since early March 2025 and the MVP done and deployed by the beginning of this month, May 2025. Initially, i vibe-coded this project using Cursor. About 50% codes are generated by Cursor. I also generate and customize most of React components using v0.&lt;/p&gt;

&lt;p&gt;I'm building it while having a full-time job, mostly in the morning before work (I'm an early bird). Cursor and v0 really helps alot here. They make the development significantly faster. Although, i still need to code manually for specific cases.&lt;/p&gt;

&lt;p&gt;The main challenges when developing Kattalog is actually not coding, but finding the right AI models to use. I literally spend about 3 weeks researching about them.&lt;/p&gt;

&lt;p&gt;I can't disclose which AI models i use for Kattalog, but i use several models from Replicate &amp;amp; Fal.ai. I didn't fine-tune or train my AI models for now, but i plan to do it later if it get some tractions. &lt;/p&gt;

&lt;p&gt;That's why i said "It's not as hard as you think" in the title. lol.&lt;/p&gt;

&lt;p&gt;You can also follow this approach to build your own SaaS. In fact, most AI Saas today use the publicly available models. So, start building your own AI project. It will be even easier if you use Cursor, even the free trial. It will help you a lot developing the prototype.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Kattalog Works
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/dRMhgzfddio"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The main functionality of Kattalog is replacing the product image background with studio-quality background with AI. Instead of doing expensive product photoshots, or photoediting, ecommerce sellers can just upload their product photo, and let Kattalog do the works.&lt;/p&gt;

&lt;p&gt;Here are the high level flows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User upload product images&lt;/li&gt;
&lt;li&gt;Kattalog will process and remove the background&lt;/li&gt;
&lt;li&gt;User open the product image with removed background in the editor&lt;/li&gt;
&lt;li&gt;User then choose a background reference, and click generate&lt;/li&gt;
&lt;li&gt;4 product images will be generated with new backgrounds. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find real examples of generated images here: &lt;a href="https://kattalog.com/examples" rel="noopener noreferrer"&gt;https://kattalog.com/examples&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main feature (background generation) is only available in paid plan. As a solo founder, i cant afford to make it free, since it cost me money to run it.&lt;/p&gt;

&lt;p&gt;But if you're an &lt;strong&gt;ecommerce seller&lt;/strong&gt; and wanted to try it, i can give you free access. Just let me know.&lt;/p&gt;

&lt;p&gt;Apart from the paid feature, there are also free features available to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Background colors&lt;/li&gt;
&lt;li&gt;Pre-generated backgrounds&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Stacks
&lt;/h2&gt;

&lt;p&gt;The stacks i used are simple. I use my favorite framework Astro, but now in SSR mode&lt;/p&gt;

&lt;h3&gt;
  
  
  The Frontend:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Astro&lt;/li&gt;
&lt;li&gt;✅ React&lt;/li&gt;
&lt;li&gt;✅ TailwindCSS&lt;/li&gt;
&lt;li&gt;✅ Shadcn / Radix&lt;/li&gt;
&lt;li&gt;✅ Konva.js for Image Editor&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Backend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Astro SSR APIs&lt;/li&gt;
&lt;li&gt;✅ PostgreSQL&lt;/li&gt;
&lt;li&gt;✅ Drizzle&lt;/li&gt;
&lt;li&gt;✅ BetterAuth&lt;/li&gt;
&lt;li&gt;✅ Cloudlfare R2 for storage&lt;/li&gt;
&lt;li&gt;✅ VPS &amp;amp; Self-hosted Coolify for deployment&lt;/li&gt;
&lt;li&gt;✅ some AI models from Replicate &amp;amp; Fal.ai&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I use Polar.sh for payment processor, since Stripe doesnt support my country (Indonesia)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Challenges
&lt;/h2&gt;

&lt;p&gt;The real challenges of building SaaS is not product development. It's product market fit. And, this is where i'm, looking for my first customers.&lt;/p&gt;

&lt;p&gt;To be fair, i didn't market it yet extensively. But, I started it today by publishing it here. Tomorrow, i will also launch Kattalog in Product Hunt.&lt;/p&gt;

&lt;p&gt;Wish me luck! :D&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you think about this project?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have any feedback, please dont hesitate to put it in the comment below.&lt;/p&gt;

&lt;p&gt;Thanks, happy building!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
      <category>startup</category>
    </item>
    <item>
      <title>Just posted this article</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Tue, 18 Mar 2025 12:25:43 +0000</pubDate>
      <link>https://dev.to/syakirurahman/just-posted-this-article-498g</link>
      <guid>https://dev.to/syakirurahman/just-posted-this-article-498g</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/syakirurahman" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F350025%2Fdeaa57e4-9e6d-48af-b514-e277d8dd00e7.jpg" alt="syakirurahman"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/syakirurahman/top-10-ai-figma-design-to-code-tools-to-build-web-app-effortlessly-3lod" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Top 10 AI Figma / Design to Code Tools to Build Web App Effortlessly&lt;/h2&gt;
      &lt;h3&gt;Syakir ・ Mar 18&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ai&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>ai</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Top 10 AI Figma / Design to Code Tools to Build Web App Effortlessly</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Tue, 18 Mar 2025 12:24:49 +0000</pubDate>
      <link>https://dev.to/syakirurahman/top-10-ai-figma-design-to-code-tools-to-build-web-app-effortlessly-3lod</link>
      <guid>https://dev.to/syakirurahman/top-10-ai-figma-design-to-code-tools-to-build-web-app-effortlessly-3lod</guid>
      <description>&lt;p&gt;Converting designs to HTML code has been a main, basic task for front-end developers. However, in today’s fast-paced development cycles, it's considered time-consuming and usually creates bottlenecks.&lt;/p&gt;

&lt;p&gt;Fortunately, AI-powered tools can now automate this task, by converting designs from tools like Figma, Adobe XD, or even raw images into production-ready code in a few clicks.&lt;/p&gt;

&lt;p&gt;For a Front-end developer like me, automating this task can significantly boost productivity. Converting a Landing page from design to code, usually take 3-4 hours. Some pages even need more time.&lt;/p&gt;

&lt;p&gt;With help of an AI design-to-code tool, we can do it in just a few minutes. We can use these saved hours for other tasks.&lt;/p&gt;

&lt;p&gt;Today, AI design-to-code tools moved from being nice-to-haves to must-have tools for developers and business to stay relevant.&lt;/p&gt;

&lt;p&gt;With that in mind, I put together the best 10 AI design to code tools you can use to speed up your web app development workflows.&lt;/p&gt;

&lt;p&gt;Before we explore every tool, here is the quick feature comparison for each tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Fidelity (pixel-perfect)&lt;/th&gt;
&lt;th&gt;Code Quality&lt;/th&gt;
&lt;th&gt;AI Capabilities&lt;/th&gt;
&lt;th&gt;Fine-tuning with Chat Prompt&lt;/th&gt;
&lt;th&gt;Code Export&lt;/th&gt;
&lt;th&gt;Freemium Options&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Anima&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Free tier)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Locofy&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Free tokens)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Builder&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Free tier)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codia&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Free tier)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v0&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Free tier)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TeleportHQ&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Free tier)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dhiwise&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (Pro plan)&lt;/td&gt;
&lt;td&gt;Yes (Basic plan)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CodeParrot&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Free trial)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fronty&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Freemium)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UX Pilot&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (Standard plan)&lt;/td&gt;
&lt;td&gt;Yes (Free credit)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Rating Explanations:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fidelity (pixel-perfect)&lt;/strong&gt;: Based on how accurately the tool converts designs into code without losing details.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Quality&lt;/strong&gt;: Reflects the cleanliness, readability, and maintainability of the generated code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Capabilities&lt;/strong&gt;: Strength of AI in generating code, handling complex designs, code personalization and providing additional features like interactivity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fine-tuning with Chat Prompt&lt;/strong&gt;: Whether the tool allow users to refine or customize the generated code using AI-powered prompts or chat-based interactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Export&lt;/strong&gt;: Whether the tool allows exporting the generated code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freemium Options&lt;/strong&gt;: Availability of free tiers or trial versions for users to test the tool before committing to a paid plan.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Now, let’s dive deeper into each tool one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;a href="https://animaapp.com" rel="noopener noreferrer"&gt;Anima&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://animaapp.com" rel="noopener noreferrer"&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%2Fchw7u4qxapxqh7bon2bc.jpg" alt="Anima Design to Code" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anima is an AI-powered design-to-code tool that bridge the gap between design and coding by converting designs from tools like Figma, Adobe XD, and Sketch into developer-friendly code.&lt;/p&gt;

&lt;p&gt;It designed to empowers designers, developers and product teams to build website faster by generating clean code with frameworks of their choice.&lt;/p&gt;

&lt;p&gt;By automating the conversion of designs into clean code, Anima enhances efficiency, reduces manual coding efforts, and accelerates the product development process&lt;/p&gt;

&lt;p&gt;Anima key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI-Powered Code Generation&lt;/strong&gt;: Utilize advanced AI to generate React code that integrates seamlessly with your existing project, maintaining consistency with your coding conventions and styles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Design Support&lt;/strong&gt;: Add breakpoints and define responsive behaviors within prototypes to ensure designs adapt to various screen sizes and devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Figma Plugin&lt;/strong&gt;: Anima can be used directly in Figma, allowing designers to generate codes for their design directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontier&lt;/strong&gt;: A VSCode Extension that bring Anima directly to VSCode, allowing developers to convert Figma design without leaving their workspace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Collaboration&lt;/strong&gt;: Sync prototypes directly from design tools, allowing designers and developers to work on the latest versions without manual file transfers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Customization&lt;/strong&gt;: Customize the generated code to align with your coding standards, ensuring the output is as familiar as if you wrote it yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With Anima
&lt;/h4&gt;

&lt;p&gt;To get started with Anima, you can create a free account &lt;a href="https://projects.animaapp.com/signup" rel="noopener noreferrer"&gt;here&lt;/a&gt;. It offers a free tier with basic features.&lt;/p&gt;

&lt;p&gt;You can start using Anima by using its &lt;a href="https://www.figma.com/community/plugin/857346721138427857" rel="noopener noreferrer"&gt;Figma plugin&lt;/a&gt;. I personally tried it by converting this &lt;a href="https://www.figma.com/community/file/1058767686059595687" rel="noopener noreferrer"&gt;free Figma landing page template&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you open the design you want to convert, select a page or component, the &lt;strong&gt;Right click&lt;/strong&gt; &amp;gt; &lt;strong&gt;Plugins&lt;/strong&gt; &amp;gt;  &lt;strong&gt;Anima&lt;/strong&gt;. An Anima plugin window will open. There you choose your coding frameworks, responsive breakpoints, etc.&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%2F7t1sexk649996mryf80k.jpg" 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%2F7t1sexk649996mryf80k.jpg" alt="Anima Figma plugin window" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you need more customization, click 'Open in Playground' button in the bottom left side.&lt;/p&gt;

&lt;p&gt;You will be redirected to Anima Playground, where you can customize your generated codes, adding logic, and even make it as your workspace.&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%2Fc11ssugqty4vw50c4hrh.jpg" 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%2Fc11ssugqty4vw50c4hrh.jpg" alt="Anima playground" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, Anima’s design-to-code tool generates pixel-perfect code, identical to the Figma design.&lt;/p&gt;

&lt;p&gt;However, things like interactivity and event handling still require manual work. This is where the Playground prompt comes in to help&lt;/p&gt;

&lt;p&gt;You can ask it to generate event handling function, code restructuring, optimization, etc. Imagination is your limit.&lt;/p&gt;

&lt;p&gt;If something goes wrong because of your prompt, you can just undo it.&lt;/p&gt;

&lt;p&gt;Once you're done, you can either download all your project codes, or publish it in Anima. They also have hosting service with custom domain options.&lt;/p&gt;

&lt;p&gt;To access all powerful Anima feature and make it your workspace, you need to at least upgrade your plan to Pro.&lt;/p&gt;

&lt;p&gt;Here are the Anima subscription plan details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt;. Cost $0, suitable for hobby projects, prototypes, and testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt;. Cost $24 per seat per month, designed for exporting code for full flows and website publishing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business&lt;/strong&gt;. Starts at $150 per month, ideal for teams building at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise&lt;/strong&gt;. Custom pricing, tailored for mature teams needing secure and scalable solutions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;a href="https://locofy.ai" rel="noopener noreferrer"&gt;Locofy&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://locofy.ai" rel="noopener noreferrer"&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%2Fdcvqdcgzcmnw26yzrbgv.jpg" alt="Locofy" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Locofy is an AI-powered design-to-code platform that transforms Figma and Adobe XD designs into production-ready code, in frameworks like React, Next.js, Gatsby, Vue, Angular and even React Native.&lt;/p&gt;

&lt;p&gt;Locofy enables designers and developers to collaborate seamlessly by generating responsive front-end code for web and mobile applications.&lt;/p&gt;

&lt;p&gt;It promises to make Front-end development up to 10x faster than traditional approach.&lt;/p&gt;

&lt;p&gt;Locofy leverages advanced AI to transform static designs into functional code efficiently. Its Key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-Click Code Generation&lt;/strong&gt;: With Locofy Lightning, users can convert designs into code with a single click, utilizing Large Design Models (LDMs) for high-quality output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Design Support&lt;/strong&gt;: The platform ensures that generated code is responsive, adapting to various screen sizes and devices without additional modifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusable Components&lt;/strong&gt;: Locofy enables the creation of reusable code components, promoting scalability and maintainability in development projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Preview and Prototyping&lt;/strong&gt;: Users can instantly preview the generated code and interact with prototypes, facilitating quick iterations and refinements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With Locofy
&lt;/h4&gt;

&lt;p&gt;Locofy has subscription plans based on LDMToken credits. All plans offer first free 1000 LDMTokens, and will need payment details on registration.&lt;/p&gt;

&lt;p&gt;Here are their subscription plans.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pay-As-You-Go (PAYG)&lt;/strong&gt;. Cost $0.050 per LDMtoken, with the first 1,000 tokens free.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freelancers &amp;amp; Bootstrappers&lt;/strong&gt;. Cost $250 billed annually (approximately $21/month), includes 5,550 LDMtokens at $0.045 per token, plus 1,000 tokens free.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Startups &amp;amp; Pros&lt;/strong&gt;. Cost $500 billed annually (approximately $42/month), includes 13,300 LDMtokens at $0.038 per token, plus 1,000 tokens free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Businesses &amp;amp; Agencies&lt;/strong&gt;. Cost $1,000 billed annually (approximately $83/month), includes 33,200 LDMtokens at $0.030 per token, plus 1,000 tokens free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprises&lt;/strong&gt;. Custom pricing available with unlimited LDMtokens and seats.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be able to get started for Free you can choose the Pay as You Go model and use your first 1000 LDMTokens.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;a href="https://www.builder.io/" rel="noopener noreferrer"&gt;Builder&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.builder.io/" rel="noopener noreferrer"&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%2Fur3t07jv36qmfpgv5tv6.jpg" alt="Builder Visual Development Platform" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Builder is a Visual Development Platform that offers an AI-powered design-to-code tool, a visual editor, and an enterprise headless CMS.&lt;/p&gt;

&lt;p&gt;Designed for both developers and non-developers, it helps teams accelerate digital projects by converting designs into code, enabling visual editing, and efficiently managing content across multiple platforms.&lt;/p&gt;

&lt;p&gt;By using Builder, organizations can streamline workflows, reduce reliance on engineering resources, and bring ideas to production faster.&lt;/p&gt;

&lt;p&gt;While it offers more than just Design-to-Code capabilities, its Design-to-Code features include::&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Design-to-Code with multiframeworks support&lt;/strong&gt;: Transforms Figma designs into clean, semantic code, supporting frameworks such as React, Vue, Angular, and more. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component Mapping&lt;/strong&gt;: Automatically reuses existing code components when available, ensuring consistency with your current codebase and reducing redundancy. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Instructions&lt;/strong&gt;: Allows developers to refine code output at the developer or team level, tailoring the generated code to match specific coding standards and preferences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Design Support&lt;/strong&gt;: Ensures that generated code is responsive, adapting to various screen sizes and devices without additional modifications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With Builder
&lt;/h4&gt;

&lt;p&gt;To get started with Builder, you can sign up for a free account on &lt;a href="https://builder.io" rel="noopener noreferrer"&gt;their website&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Here are their subscription plans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt;. Ideal for individuals and teams working on smaller projects, free for up to 10 users.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt;. Designed for teams building larger projects, $19 per user per month with scalable usage options.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise&lt;/strong&gt;. Tailored for organizations requiring more scale, control, and support, with custom pricing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As your needs grow, you can choose from scalable pricing plans to move faster and fuel sustainable growth. &lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;a href="https://codia.ai/design-to-code" rel="noopener noreferrer"&gt;Codia&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://codia.ai/design-to-code" rel="noopener noreferrer"&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%2Fny4s8k11jdtljbb9w62u.jpg" alt="Codia AI Powored Design to Code" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Codia is an AI-powered platform that transforms Figma designs into production-ready code for both web and mobile applications. &lt;/p&gt;

&lt;p&gt;It can convert designs to pure HTML/CSS, Tailwind, React, Vue for web development, and iOS, Android, Flutter, Swift, SwiftUI, Objective-C, Java, Kotlin for mobile development.&lt;/p&gt;

&lt;p&gt;Codia works as a plugin on &lt;a href="https://www.figma.com/community/plugin/1301565000406306598" rel="noopener noreferrer"&gt;Figma&lt;/a&gt;, where you can work and collaborate with other designers or developers&lt;/p&gt;

&lt;p&gt;Its key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI-Powered Code Generation&lt;/strong&gt;: Converts Figma designs into functional code, reducing development time and bridging the gap between designers and developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Platform Support&lt;/strong&gt;: Generates high-quality, production-ready code for various web platforms, mobile apps, and the Flutter cross-platform framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-Powered Design Tools&lt;/strong&gt;: Assists designers from conceptualization to final design, using advanced visual AI technology and large language models to understand and generate designs from textual or image inputs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With Codia
&lt;/h4&gt;

&lt;p&gt;To begin using Codia, install the Codia Figma Plugin by searching for "Codia" in Figma's plugin menu or by visiting the plugin's page directly. &lt;/p&gt;

&lt;p&gt;Once installed, open your design file, run the plugin, and select your target platform and framework.&lt;/p&gt;

&lt;p&gt;The AI will then generate the corresponding code, which you can download or preview in CodeSandbox.&lt;/p&gt;

&lt;p&gt;If you're going to use Codia for real world projects, the Free version might be not enough, since it's AI capabilities are limited.&lt;/p&gt;

&lt;p&gt;Summarized from their pricing page for AI Design-to-Code, here are the subscription details for Codia:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt;. Free forever, ideal for students, educators, and freelancers, offering 30 AI code generations per day and 5 AI code export credits upon sign-up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starter&lt;/strong&gt;. Designed for beginner developers at $29/ developer/month ($17 if paid anually), with unlimited AI code generations and 300 AI code export credits per month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt;. Tailored for professional developers and teams at $49/developer/month ($29 if paid anually), providing enhanced features and support.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. &lt;a href="https://v0.dev" rel="noopener noreferrer"&gt;v0&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://v0.dev" rel="noopener noreferrer"&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%2Fjgwzc4sfkm7vj2qws3yz.jpg" alt="vO" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;v0 is an AI-powered tool developed by Vercel specialized in Code generation based on user prompt. &lt;/p&gt;

&lt;p&gt;With v0, You can generate a fully functional app simply based on prompts. It supports frameworks like React, Next.js, Tailwind, and Shadcn, with ability to preview the generated code.&lt;/p&gt;

&lt;p&gt;v0 also offers a feature that converts images or designs into code to some extent, enhancing its versatility in design-to-code workflows.&lt;/p&gt;

&lt;p&gt;Its key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generative UI&lt;/strong&gt;: Create user interfaces by describing requirements, producing high-quality React code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-Driven Code Generation&lt;/strong&gt;: Utilize advanced AI technology to generate code, saving time and effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatibility&lt;/strong&gt;: Seamlessly integrate with Shadcn UI and Tailwind CSS, ensuring easy adoption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizable Options&lt;/strong&gt;: Access multiple AI-generated interface designs that can be tailored to specific needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rapid Prototyping&lt;/strong&gt;: Facilitate quick iteration and testing of new product ideas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With v0
&lt;/h4&gt;

&lt;p&gt;To begin using v0, visit the &lt;a href="https://v0.dev/" rel="noopener noreferrer"&gt;official website&lt;/a&gt; and sign up for an account. Once registered, you can input text descriptions or upload images/designs to generate corresponding components. &lt;/p&gt;

&lt;p&gt;The platform provides real-time previews, allowing you to customize and refine the generated code before integrating it into your projects.&lt;/p&gt;

&lt;p&gt;To convert design to code, you can select the 'import from Figma' button. Fill it with your Figma design selection link. It will import your design.&lt;/p&gt;

&lt;p&gt;Note that the imported figma design size is limited based on your plan. For larger files, you might need to update your subscription plan&lt;/p&gt;

&lt;p&gt;Here are their subscription plans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt;. For individuals exploring the platform, priced at $0/month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Premium&lt;/strong&gt;. Offers higher messaging limits for $20/month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team&lt;/strong&gt;. Designed for collaborative teams at $30/user/month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise&lt;/strong&gt;. Tailored for companies needing robust security and performance, with custom pricing[8].&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. &lt;a href="https://teleporthq.io/" rel="noopener noreferrer"&gt;TeleportHQ&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://teleporthq.io/" rel="noopener noreferrer"&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%2Fkwud4irry0ezellbhdrc.jpg" alt="TeleportHQ" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TeleportHQ is an AI-powered collaborative front-end platform, offering a powerful visual builder to create and publish static and dynamic websites instantly. &lt;/p&gt;

&lt;p&gt;It supports seamless collaboration with features like real-time code generation, Figma integration, and multiple frameworks supports like React, Next.js, Vue, and Angular. &lt;/p&gt;

&lt;p&gt;It also offer hosting service for the project you develop there.&lt;/p&gt;

&lt;p&gt;Its key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI-Powered Website Builder&lt;/strong&gt;: Leverages OpenAI-generated code to create web pages based on user prompts. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Figma Integration&lt;/strong&gt;: Converts Figma designs into functional code with direct import and further customization within TeleportHQ. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Collaboration&lt;/strong&gt;: Provides a shared workspace for designers and developers to work together in real-time. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible Code Export&lt;/strong&gt;: Allows exporting of final code in various JavaScript frameworks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced Customization&lt;/strong&gt;: Offers control over design elements with an intuitive Style Inspector Panel and CSS classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With TeleportHQ
&lt;/h4&gt;

&lt;p&gt;To begin with TeleportHQ, visit their official website and sign up for a free account. &lt;/p&gt;

&lt;p&gt;Once registered, you can start creating projects using their visual builder, import designs from Figma, and collaborate with team members in real-time. &lt;/p&gt;

&lt;p&gt;Here are their subscription plans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt;. Perfect for getting started, allows building, sharing, and publishing projects at $0 forever.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional&lt;/strong&gt;. For teams needing collaboration on complex projects with custom domains, priced at $9/editor/month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agency&lt;/strong&gt;. Tailored for agencies handling numerous projects with unique hosting needs; custom pricing is available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For users seeking technical assistance, TeleportHQ offers dedicated support and training sessions ranging from $80 for a 1-hour session to $480 for an 8-hour session. &lt;/p&gt;

&lt;h3&gt;
  
  
  7. &lt;a href="https://www.dhiwise.com/design-converter" rel="noopener noreferrer"&gt;Dhiwise Design Converter&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.dhiwise.com/design-converter" rel="noopener noreferrer"&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%2F8en000pcae81mzis9os5.jpg" alt="Dhiwise Design Converter" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dhiwise Design Converter is an AI powered tool to translate Figma designs into code for frameworks like React, Next.js, Flutter, and Shopify Liquid, with full support for responsive, modular code generation.&lt;/p&gt;

&lt;p&gt;It helps developers save significant time by automating repetitive tasks, ensuring that the generated code is scalable, consistent, and ready for deployment across multiple devices.&lt;/p&gt;

&lt;p&gt;It works as a plugin in Figma and an Editor in their website.&lt;/p&gt;

&lt;p&gt;Its Key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Figma to Code Conversion&lt;/strong&gt;: Translate Figma designs into clean, modular code with automatic layer and component mapping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Support for Multiple Frameworks&lt;/strong&gt;: Tailored code generation for frameworks like React, Next.js, Flutter, and Shopify Liquid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Responsiveness&lt;/strong&gt;: Generates responsive layouts optimized for different screen sizes without additional coding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Design System Integration&lt;/strong&gt;: Sync with popular design systems like Tailwind and Chakra for consistent styling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Preview and Collaboration&lt;/strong&gt;: Share interactive previews for real-time feedback from teams and stakeholders.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With Dhiwise Design Converter
&lt;/h4&gt;

&lt;p&gt;To get started, register on Dhiwise's platform, then link your Figma design file for automatic conversion. &lt;/p&gt;

&lt;p&gt;Here are their subscription plans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Basic&lt;/strong&gt;. Free forever, allowing you to build unlimited apps, but you cant export them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt;. Priced at $149 per user per year (billed annually), it unlocks export code for 30 screens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise&lt;/strong&gt;. Offers custom pricing based on your specific needs, enabling export code for 1,000+ screens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8. &lt;a href="https://codeparrot.ai" rel="noopener noreferrer"&gt;CodeParrot&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://codeparrot.ai" rel="noopener noreferrer"&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%2Flifob35y984ddm54v17z.jpg" alt="Screen Shot 2025-02-03 at 23.04.33 copy" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CodeParrot is an AI-driven platform that transforms Figma designs and screenshots into production-ready front-end code, enabling developers to build stunning user interfaces quickly.&lt;/p&gt;

&lt;p&gt;It supports various tech stacks, including React, Angular, Vue.js, and more, allowing seamless integration into existing projects.&lt;/p&gt;

&lt;p&gt;CodeParrot works as &lt;a href="https://marketplace.visualstudio.com/items?itemName=CodeParrot-ai.CodeParrot" rel="noopener noreferrer"&gt;VSCode Extension&lt;/a&gt;, allowing developers to use convert design to code without leaving their workspace.&lt;/p&gt;

&lt;p&gt;Its key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Figma to Code&lt;/strong&gt;: Converts Figma designs into clean, production-ready code, streamlining the development process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screenshot to Code&lt;/strong&gt;: Transforms screenshots into code, allowing developers to recreate designs from images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codebase Integration&lt;/strong&gt;: Integrates with existing themes, components, and libraries, ensuring consistency with your project's coding standards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Chat Assistant&lt;/strong&gt;: Provides an AI-powered chat assistant to assist with code generation and troubleshooting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With CodeParrot
&lt;/h4&gt;

&lt;p&gt;To get started with CodeParrot, you can directly install &lt;a href="https://marketplace.visualstudio.com/items?itemName=CodeParrot-ai.codeParrot" rel="noopener noreferrer"&gt;CodeParrot Extensition&lt;/a&gt; to your VSCode.&lt;/p&gt;

&lt;p&gt;Then, Login with your Figma account to be able to Select your figma design directly from VSCode.&lt;/p&gt;

&lt;p&gt;At this point, you will activate your free trial account. After 14 days, you will have to pay for their subscription plan to continue using it.&lt;/p&gt;

&lt;p&gt;Here are their subscription plans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt;: At $19 per seat per month, this plan includes Figma to code, screenshot to code, custom themes, custom components, and an AI chat assistant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team&lt;/strong&gt;: Priced at $39 per seat per month (minimum of 3 seats), it offers all Pro features plus integration with your project's theme, components, and coding standards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise&lt;/strong&gt;: This plan includes all Team features, on-prem deployment, and zero data retention. Pricing is available upon request.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  9. &lt;a href="https://fronty.com/" rel="noopener noreferrer"&gt;Fronty&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://fronty.com/" rel="noopener noreferrer"&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%2F385gssfw50ii3uomfo49.jpg" alt="Fronty" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fronty is an AI-powered tool that converts images into HTML and CSS code, enabling users to create websites quickly without any coding experience.&lt;/p&gt;

&lt;p&gt;By just uploading an image, Fronty's AI analyzes the design and generates clean, standards-compliant HTML and CSS code within minutes.&lt;/p&gt;

&lt;p&gt;Its key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI-Powered Image to HTML/CSS Conversion&lt;/strong&gt;: Automatically transforms your uploaded images into clean, responsive HTML and CSS code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No-Code Online Editor&lt;/strong&gt;: Offers an intuitive editor to customize and manage website content and generated codes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive and SEO-Friendly Design&lt;/strong&gt;: Ensures that generated websites are mobile-friendly, optimized for search engines, and adhere to best practices for performance and accessibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting and Custom Domain Support&lt;/strong&gt;: Provides hosting services with features like custom domain attachment, regular backups, and high uptime, allowing users to publish their websites directly through Fronty.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With Fronty
&lt;/h4&gt;

&lt;p&gt;To begin using Fronty, visit their website and sign up for an account. &lt;/p&gt;

&lt;p&gt;Once registered, you can upload an design image, and Fronty's AI will generate the corresponding HTML and CSS code. &lt;/p&gt;

&lt;p&gt;You can then use the no-code editor to customize your website's content and design before publishing it online.&lt;/p&gt;

&lt;p&gt;Fronty offers various subscription plans to accommodate different user needs. Here are their subscription plans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Freemium&lt;/strong&gt;. Free for up to 3 users, includes a free subdomain and limited hosting with Fronty branding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt;. Costs $4.52/monthly, supports up to 10 users, offers custom domain, no Fronty branding, and increased hosting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced&lt;/strong&gt;. Priced at $9/monthly, suitable for up to 25 users, providing more hosting and all the features of the Pro plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For detailed information on each plan and to choose the one that best fits your requirements, please visit &lt;a href="https://fronty.com/pricing/" rel="noopener noreferrer"&gt;Fronty's pricing page&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  10. &lt;a href="https://uxpilot.ai/image-to-html-code-generator" rel="noopener noreferrer"&gt;UX Pilot&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://uxpilot.ai/image-to-html-code-generator" rel="noopener noreferrer"&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%2Fg4q3vx5o30zaq7tyfoa6.jpg" alt="UX Pilot" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;UX Pilot is an AI-powered UX/UI design platform that enables users to create high-fidelity designs and wireframes swiftly. &lt;/p&gt;

&lt;p&gt;It's designed to assist UX professionals, product teams, and founders in generating high-quality designs efficiently, then convert them into functional codes. &lt;/p&gt;

&lt;p&gt;While, it's mainly designed for designers, its design to code tool is quite powerful to reduce manual coding works. &lt;/p&gt;

&lt;p&gt;Its key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI-Based UX Design Review&lt;/strong&gt;: Provides actionable insights to enhance design quality. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Workshop Generation&lt;/strong&gt;: Generates tailored workshops to address specific UX challenges. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Fidelity UI Design Generation&lt;/strong&gt;: Instantly creates pixel-perfect screens, expediting the design process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Wireframer&lt;/strong&gt;: Produces flexible wireframes for both desktop and mobile platforms, facilitating quick exploration of design concepts. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image to HTML/CSS Conversion&lt;/strong&gt;: Automatically converts images or designs into HTML/CSS code using AI, streamlining the transition from design to development. &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Getting Started With UX Pilot
&lt;/h4&gt;

&lt;p&gt;To begin using UX Pilot, visit &lt;a href="https://uxpilot.ai" rel="noopener noreferrer"&gt;their official website&lt;/a&gt; and sign up for a free account. The platform offers a free trial, allowing users to explore its features before committing to a subscription. &lt;/p&gt;

&lt;p&gt;Here are their subscription plans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt;. $0/month, offering a one-time allocation of 30 credits for up to 5 screens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard&lt;/strong&gt;. $12/month, providing 420 credits for up to 70 screens, including export to Figma and code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt;. $22/month, increasing the credit allocation to 1200 for up to 200 screens, unlocking unlimited screen flows, and image-to-design functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;We have discussed some of the best AI-powered tools that will convert your designs into clean, production-ready code. Such tools now power how developers and designers work together way faster and much more efficiently.&lt;/p&gt;

&lt;p&gt;Of course, no tool is perfect, and AI-generated code might still need some refinements.  However, the first tool on our list, Anima, offers a chat-based prompting feature for advanced code iteration and customization after conversion with live preview.&lt;/p&gt;

&lt;p&gt;That’s why we ranked it first as it’s the only design-to-code tool with this feature and the most comprehensive set of capabilities overall.&lt;/p&gt;

&lt;p&gt;If you want to optimize your workflow, this is the time to look into such tools. Give them a try, see what works for you, and start building faster.&lt;/p&gt;

&lt;p&gt;And if you've used one, share-what did work, what didn't, and what surprised you most!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Wed, 05 Feb 2025 22:49:16 +0000</pubDate>
      <link>https://dev.to/syakirurahman/-29o4</link>
      <guid>https://dev.to/syakirurahman/-29o4</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/strapi" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&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%2Forganization%2Fprofile_image%2F763%2F988af53b-5d7e-435a-98eb-dd4aff5299d2.png" alt="Strapi" width="600" height="600"&gt;
      &lt;div class="ltag__link__user__pic"&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%2Fuser%2Fprofile_image%2F350025%2Fdeaa57e4-9e6d-48af-b514-e277d8dd00e7.jpg" alt="" width="412" height="412"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/strapi/remix-tutorial-building-a-simple-contact-app-with-strapi-as-backend-407p" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Remix Tutorial: Building A Simple Contact App With Strapi as Backend&lt;/h2&gt;
      &lt;h3&gt;Syakir for Strapi ・ Feb 5&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Remix Tutorial: Building A Simple Contact App With Strapi as Backend</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Wed, 05 Feb 2025 12:02:47 +0000</pubDate>
      <link>https://dev.to/strapi/remix-tutorial-building-a-simple-contact-app-with-strapi-as-backend-407p</link>
      <guid>https://dev.to/strapi/remix-tutorial-building-a-simple-contact-app-with-strapi-as-backend-407p</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this Remix tutorial, we’ll walk through how to build a simple contact app using Remix for the frontend and Strapi headless CMS as the backend. You’ll learn how to set up both tools, connect them, implement CRUD operations and create a working application step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting this Remix tutorial, make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js and npm installed on your machine (v18 or later recommended).&lt;/li&gt;
&lt;li&gt;A basic understanding of HTML, CSS and JavaScript.&lt;/li&gt;
&lt;li&gt;Git installed for version control.&lt;/li&gt;
&lt;li&gt;A code editor, like VS Code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you'll learn
&lt;/h2&gt;

&lt;p&gt;In this tutorial, you will learn: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to set up a Remix project and understand its core features.&lt;/li&gt;
&lt;li&gt;Setting up Strapi as a backend and integrating it with Remix.&lt;/li&gt;
&lt;li&gt;Implementing CRUD functionalities (Create, Read, Update, Delete) for a simple contact management app.&lt;/li&gt;
&lt;li&gt;Using Zod for form validation and &lt;code&gt;useNavigate&lt;/code&gt; for navigation actions.&lt;/li&gt;
&lt;li&gt;Adding advanced features like search, sorting, pagination, and favorite functionality.&lt;/li&gt;
&lt;li&gt;Handling errors, creating a 404 fallback, and improving user experience with loading states and debouncing.&lt;/li&gt;
&lt;li&gt;Exploring additional improvements such as highlighting selected contacts and using &lt;code&gt;useFetcher&lt;/code&gt; for better interactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What we're building
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we’ll build a simple contact management app with features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contact List and Detail View&lt;/strong&gt;: Display all contacts and view details for each contact. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CRUD Operations&lt;/strong&gt;: Add, edit, update, and delete contact information seamlessly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Favorite Marking&lt;/strong&gt;: Mark contacts as favorites for easier organization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search Functionality&lt;/strong&gt;: Implement real-time search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling and 404 Pages&lt;/strong&gt;: Handle missing data and server errors gracefully with custom fallback pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced User Experience&lt;/strong&gt;: Add features like loading states and highlighting selected contacts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started with Remix
&lt;/h2&gt;

&lt;p&gt;Remix is a React-based framework for building fast, dynamic web apps with seamless server and client rendering. It simplifies routing, data loading, and error handling while focusing on performance, web standards, and accessibility&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Remix project
&lt;/h3&gt;

&lt;p&gt;To make it simple, we will refer to the official remix documentation to setup remix project.&lt;/p&gt;

&lt;p&gt;We will also use the official remix tutorial project. Later, we will integrate this tutorial project with Strapi as backend.&lt;/p&gt;

&lt;p&gt;First, let's create a project folder &lt;code&gt;remix-strapi&lt;/code&gt;, and open it in the Terminal. This folder will contains 2 forlders for remix (frontend) and strapi (backend).&lt;/p&gt;

&lt;p&gt;Before setting up remix and strapi backend, we will initialize git repository in this folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, set up a remix project by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-remix@latest &lt;span class="nt"&gt;--template&lt;/span&gt; remix-run/remix/templates/remix-tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will prompt you with some questions in your terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Need to &lt;span class="nb"&gt;install &lt;/span&gt;the following packages:
create-remix@2.15.1
Ok to proceed? &lt;span class="o"&gt;(&lt;/span&gt;y&lt;span class="o"&gt;)&lt;/span&gt; y


 remix   v2.15.1 💿 Let&lt;span class="s1"&gt;'s build a better website...

   dir   Where should we create your new project?
         ./remix

      ◼  Template: Using remix-run/remix/templates/remix-tutorial...
      ✔  Template copied

   git   Initialize a new git repository?
         No

  deps   Install dependencies with npm?
         Yes

      ✔  Dependencies installed

  done   That'&lt;/span&gt;s it!

         Enter your project directory using &lt;span class="nb"&gt;cd&lt;/span&gt; ./remix
         Check out README.md &lt;span class="k"&gt;for &lt;/span&gt;development and deploy instructions.

         Join the community at https://rmx.as/discord

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

&lt;/div&gt;



&lt;p&gt;We named the project folder remix. Select &lt;code&gt;No&lt;/code&gt; for Git repository initialization, as we have already initialized Git in the parent folder, &lt;code&gt;remix-strapi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let's open &lt;code&gt;remix-strapi&lt;/code&gt; in VSCode. You'll find a &lt;code&gt;remix&lt;/code&gt; folder inside. Under the &lt;code&gt;remix&lt;/code&gt; folder, there will be an &lt;code&gt;app&lt;/code&gt; folder where application code is located.&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%2Frx5p6895dovhx5ri2v2n.jpg" 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%2Frx5p6895dovhx5ri2v2n.jpg" alt="Inside remix folder.jpg" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;code&gt;root.tsx&lt;/code&gt; is the entry point of the application. We will refer to this as the "Root route"&lt;/li&gt;
&lt;li&gt; &lt;code&gt;data.ts&lt;/code&gt; store the functions related to data operations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app.css&lt;/code&gt; is the main CSS file for styling the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's run our Remix app. Right-click on the &lt;code&gt;remix&lt;/code&gt; folder and select &lt;code&gt;Open in Integrated Terminal&lt;/code&gt;. This will open the terminal in your VSCode.&lt;/p&gt;

&lt;p&gt;Run the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Remix app will start on &lt;code&gt;localhost:5173&lt;/code&gt;, but you will see an unstyled page.&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%2Fw8lvy9h8d28znhn6ais3.jpg" 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%2Fw8lvy9h8d28znhn6ais3.jpg" alt="Remix unstyled page.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is because we haven't imported the &lt;code&gt;app.css&lt;/code&gt; file in &lt;code&gt;root.tsx&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Importing CSS in Root route
&lt;/h3&gt;

&lt;p&gt;Let's import the &lt;code&gt;app.css&lt;/code&gt; in &lt;code&gt;root.tsx&lt;/code&gt; by adding the code on lines 9–13 as shown below.&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;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Scripts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ScrollRestoration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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;LinksFunction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;appStyleHref&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;./app.css?url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LinksFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stylesheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appStyleHref&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charSet&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Links&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sidebar"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        ...
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ScrollRestoration&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Scripts&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&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;Refresh the app, and it will render the styles.&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%2F6fd1j4v0jfrrhgyfrjxa.jpg" 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%2F6fd1j4v0jfrrhgyfrjxa.jpg" alt="Styled page.jpg" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on a contact in the list, and you will see a 404 Not Found page. This happens because we haven't set up the routes for it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Routes in Remix
&lt;/h3&gt;

&lt;p&gt;Now, let's create a new folder named &lt;code&gt;routes&lt;/code&gt; to store all the page routes we plan to add.&lt;/p&gt;

&lt;p&gt;We'll start by creating a &lt;code&gt;/contacts&lt;/code&gt; route.&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%2Fz2910jz5g4vqvh5y0yqk.jpg" 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%2Fz2910jz5g4vqvh5y0yqk.jpg" alt="Contact route.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, we have to add the &lt;code&gt;&amp;lt;Outlet /&amp;gt;&lt;/code&gt; component in the &lt;code&gt;root.tsx&lt;/code&gt; to render the route component.&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;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Outlet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Scripts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ScrollRestoration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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;LinksFunction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;appStyleHref&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;./app.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LinksFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stylesheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appStyleHref&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charSet&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Links&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sidebar"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        ...
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Outlet&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ScrollRestoration&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Scripts&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&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;First, we need to import &lt;code&gt;Outlet&lt;/code&gt; from &lt;code&gt;@remix-run/react&lt;/code&gt;, as shown on line 5 in the code above. Then, use the &lt;code&gt;&amp;lt;Outlet /&amp;gt;&lt;/code&gt; component, as shown on lines 30–32 in the code above.&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%2Fnkyqo2krkjyencx7iusy.jpg" 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%2Fnkyqo2krkjyencx7iusy.jpg" alt="Static route.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see that it now renders the &lt;code&gt;ContactsRoute&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;However, this is just a static route. Static routes are used to display static content in your web application.&lt;/p&gt;

&lt;p&gt;If you click a contact in the sidebar, you will still see a &lt;code&gt;404 Not Found&lt;/code&gt; error page. This is because it's expecting a dynamic route.&lt;/p&gt;

&lt;p&gt;To create a dynamic route, simply rename the file &lt;code&gt;contacts.tsx&lt;/code&gt; to &lt;code&gt;contacts.$contactId.tsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, click a contact in the sidebar again. This time, it won't render the &lt;code&gt;404 Not Found&lt;/code&gt; error page.&lt;/p&gt;

&lt;p&gt;The number &lt;code&gt;1&lt;/code&gt; in &lt;code&gt;/contacts/1&lt;/code&gt; will be passed as the &lt;code&gt;$contactId&lt;/code&gt; parameter to the &lt;code&gt;ContactsRoute&lt;/code&gt; component. We'll use it to fetch contact data in the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Contact Detail Page
&lt;/h3&gt;

&lt;p&gt;Before we work on the data fetching, let's now create a proper component for contact detail page first.&lt;/p&gt;

&lt;p&gt;Change all codes in the &lt;code&gt;contacts.$contactId.tsx&lt;/code&gt; component with this code.&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;Form&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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;FunctionComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="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;ContactRecord&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Contact&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;contact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://placecats.com/200/200&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your_handle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some notes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;favorite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contact"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
          &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; avatar`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&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;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;No Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Favorite&lt;/span&gt; &lt;span class="na"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
              &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://twitter.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notes&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/contacts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/edit`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"buttonLink"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Edit&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;
            &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"delete"&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;
            &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please confirm you want to delete this record.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
              &lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Favorite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pick&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ContactRecord&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;favorite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;favorite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favorite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;favorite&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Remove from favorites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Add to favorites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"favorite"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;favorite&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;favorite&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;★&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;☆&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&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;In the code above,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; We use a dummy contact data, stored it in &lt;code&gt;contact&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt; In the component markup, we render contact fields in UI.&lt;/li&gt;
&lt;li&gt; We added a &lt;code&gt;Favorite&lt;/code&gt; component, Edit and Delete button. For now, they dont have any functionality yet. We will implement theme later in this tutorial.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code will render this page. It's currently displaying a dummy contact, but soon we'll make it load the actual contact based on the ID in the URL.&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%2Fdbn1fd9gka5euvlew6gf.jpg" 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%2Fdbn1fd9gka5euvlew6gf.jpg" alt="Contact detail.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Loader Function to Load Data
&lt;/h3&gt;

&lt;p&gt;Before using real data, we'll use the dummy contact data stored in &lt;code&gt;data.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's go back to &lt;code&gt;root.tsx&lt;/code&gt;. We'll load the contact list in the sidebar from the dummy data.&lt;/p&gt;

&lt;p&gt;First, import the &lt;code&gt;getContacts&lt;/code&gt; function from &lt;code&gt;./data.ts&lt;/code&gt; and use it in a loader function.&lt;/p&gt;

&lt;p&gt;Then, loop through the fetched contacts data inside the &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt; element in the sidebar.&lt;/p&gt;

&lt;p&gt;Here is the updated &lt;code&gt;root.tsx&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;Form&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;Links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Outlet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Scripts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ScrollRestoration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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;type&lt;/span&gt; &lt;span class="nx"&gt;LinksFunction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;appStyleHref&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;./app.css&lt;/span&gt;&lt;span class="dl"&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;getContacts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LinksFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stylesheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appStyleHref&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;const&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contacts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getContacts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contacts&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contacts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charSet&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Links&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sidebar"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Remix Contacts&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search-form"&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;
                &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Search contacts"&lt;/span&gt;
                &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Search"&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;
              &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search-spinner"&lt;/span&gt; &lt;span class="na"&gt;aria-hidden&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;New&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`contacts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
                          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;/&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;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;No Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favorite&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;★&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&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;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;No contacts&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Outlet&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ScrollRestoration&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Scripts&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&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;The loader function should be explicitly exported as &lt;code&gt;loader&lt;/code&gt; to work.&lt;/p&gt;

&lt;p&gt;It returns the &lt;code&gt;contacts&lt;/code&gt; from the dummy data, allowing us to fetch it using &lt;code&gt;useLoaderData&lt;/code&gt; in the main component.&lt;/p&gt;

&lt;p&gt;Refresh the page, it will render the contact list in the sidebar.&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%2Fc16r2vo4mfhw429sp6t3.jpg" 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%2Fc16r2vo4mfhw429sp6t3.jpg" alt="Contact list in sidebar.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Loading Single Contact based on Id param
&lt;/h3&gt;

&lt;p&gt;Now, we're going to fetch contact data based on the id param in the url.&lt;/p&gt;

&lt;p&gt;We just need to add another loader function, but this time with contactId parameter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FunctionComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getContact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ContactRecord&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../data&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;invariant&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tiny-invariant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;invariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing contactId param&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;contact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contact&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Contact&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contact&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The loader function has a &lt;code&gt;{ params }&lt;/code&gt; argument that contains the &lt;code&gt;contactId&lt;/code&gt; parameter from the URL. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;invariant&lt;/code&gt; is a utility function used to verify whether the contact ID parameter exists in the URL. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;getContact&lt;/code&gt; function from &lt;code&gt;/data.ts&lt;/code&gt; is used to fetch individual contact data based on the &lt;code&gt;contactId&lt;/code&gt; parameter. If the contact is not found, it returns a &lt;code&gt;Not Found&lt;/code&gt; error.&lt;/li&gt;
&lt;li&gt;In the main component, we replace the dummy contact with &lt;code&gt;useLoaderData&lt;/code&gt;. There are no changes to the component markup. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up Strapi as Backend
&lt;/h2&gt;

&lt;p&gt;Strapi is an open-source headless CMS designed to simplify content management and API creation for developers. It offers an intuitive admin panel, allowing users to create custom content types and manage data seamlessly while supporting RESTful and GraphQL APIs for flexible integration with any frontend framework.&lt;/p&gt;

&lt;p&gt;We will use Strapi backend to store our contacts data and fetch it in remix app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Strapi to the Project
&lt;/h3&gt;

&lt;p&gt;First, let's set up the Strapi project.&lt;/p&gt;

&lt;p&gt;Navigate to the root project folder, remix-strapi, in your terminal. If your terminal is currently in the remix folder, you can switch to the remix-strapi folder by running cd ../.&lt;/p&gt;

&lt;p&gt;Once in the remix-strapi folder, run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-strapi@latest my-strapi-project&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It will prompt you with some questions again&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Need to &lt;span class="nb"&gt;install &lt;/span&gt;the following packages:
create-strapi@5.5.1
Ok to proceed? &lt;span class="o"&gt;(&lt;/span&gt;y&lt;span class="o"&gt;)&lt;/span&gt; y


 Strapi   v5.5.1 🚀 Let&lt;span class="s1"&gt;'s create your new project


We can'&lt;/span&gt;t find any auth credentials &lt;span class="k"&gt;in &lt;/span&gt;your Strapi config.

Create a free account on Strapi Cloud and benefit from:

- ✦ Blazing-fast ✦ deployment &lt;span class="k"&gt;for &lt;/span&gt;your projects
- ✦ Exclusive ✦ access to resources to make your project successful
- An ✦ Awesome ✦ community and full enjoyment of Strapi&lt;span class="s1"&gt;'s ecosystem

Start your 14-day free trial now!


? Please log in or sign up. Skip
? Do you want to use the default database (sqlite) ? Yes
? Start with an example structure &amp;amp; data? No
? Start with Typescript? Yes
? Install dependencies with npm? Yes
? Initialize a git repository? No

 Strapi   Creating a new application at /Volumes/Work/Labs/remix-strapi/my-strapi-project

   deps   Installing dependencies with npm
npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
npm warn deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
npm warn deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated mailcomposer@3.12.0: This project is unmaintained
npm warn deprecated buildmail@3.10.0: This project is unmaintained
npm warn deprecated boolean@3.2.0: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

added 1372 packages, and audited 1373 packages in 3m

200 packages are looking for funding
  run `npm fund` for details

4 low severity vulnerabilities

Some issues need review, and may require choosing
a different dependency.

Run `npm audit` for details.

       ✓  Dependencies installed

 Strapi   Your application was created!
          Available commands in your project:

          Start Strapi in watch mode. (Changes in Strapi project files will trigger a server restart)
          npm run develop

          Start Strapi without watch mode.
          npm run start

          Build Strapi admin panel.
          npm run build

          Deploy Strapi project.
          npm run deploy

          Display all available commands.
          npm run strapi

          To get started run

          cd /Volumes/Work/Labs/remix-strapi/my-strapi-project
          npm run develop
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the terminal prompt above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I skipped the Strapi Cloud free trial registration since we will use the project locally for demo purposes only.&lt;/li&gt;
&lt;li&gt;Chose SQLite for the database.&lt;/li&gt;
&lt;li&gt;Started with no structure or data examples.&lt;/li&gt;
&lt;li&gt;Selected TypeScript.&lt;/li&gt;
&lt;li&gt;Used npm as the dependency manager. &lt;/li&gt;
&lt;li&gt;Skipped Git initialization since we already initialized Git in the parent folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's run our Strapi project. In the terminal, navigate to the Strapi project folder &lt;code&gt;my-strapi-project&lt;/code&gt; using &lt;code&gt;cd my-strapi-project&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, run &lt;code&gt;npm run develop&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Strapi will open at &lt;code&gt;http://localhost:1337/&lt;/code&gt;. Since this is a new installation, you'll need to register an admin user before logging into the Strapi dashboard.&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%2Fth0xld8cz2p7nnivfojw.jpg" 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%2Fth0xld8cz2p7nnivfojw.jpg" alt="Strapi registration.jpg" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once registered, you will be logged into the Strapi dashboard.&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%2Fiaay13ffitf25yplbnm7.jpg" 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%2Fiaay13ffitf25yplbnm7.jpg" alt="Strapi 5 Dashboard.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take some time to explore Strapi's features and familiarize yourself with the dashboard.&lt;/p&gt;

&lt;p&gt;Some core features you should explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content-Type Builder&lt;/strong&gt;: Use this to build content types based on your needs. There are three types of content you can create:

&lt;ul&gt;
&lt;li&gt;Collection Type&lt;/li&gt;
&lt;li&gt;Single Type&lt;/li&gt;
&lt;li&gt;Component&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;By default, Strapi provides an existing &lt;code&gt;user&lt;/code&gt; collection.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content Manager&lt;/strong&gt;: Manage your content here—create, update, or delete entries after setting up your collection or other content types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Media Library&lt;/strong&gt;: Store and manage images, videos, and other media that will be used in your content.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create Contact Collection on Strapi
&lt;/h3&gt;

&lt;p&gt;Before storing contacts in Strapi, we need to create a &lt;code&gt;Contact&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;Navigate to the &lt;strong&gt;Content-Type Builder&lt;/strong&gt; and create a new &lt;code&gt;Contact&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;You will be prompted to select fields for the newly created &lt;code&gt;Contact&lt;/code&gt; collection.&lt;/p&gt;

&lt;p&gt;We will create the &lt;code&gt;Contact&lt;/code&gt; fields based on the &lt;code&gt;ContactMutation&lt;/code&gt; type, which you can find in &lt;code&gt;./data.ts&lt;/code&gt; in your Remix project, excluding the &lt;code&gt;id&lt;/code&gt; column.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ContactMutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;first&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;last&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;favorite&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://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%2Faldiimgby14z2lfeyc0b.jpg" 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%2Faldiimgby14z2lfeyc0b.jpg" alt="Contact Collection.jpg" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All fields we created have the &lt;code&gt;Text (Short text)&lt;/code&gt; type, except for &lt;code&gt;notes&lt;/code&gt;, which is &lt;code&gt;Text (Long text)&lt;/code&gt;, and &lt;code&gt;favorite&lt;/code&gt;, which is &lt;code&gt;Boolean&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Save the collection, and now we can start adding contact data to Strapi.&lt;/p&gt;

&lt;p&gt;Navigate to the &lt;strong&gt;Content Manager&lt;/strong&gt; menu. Select the &lt;code&gt;Contact&lt;/code&gt; collection and choose &lt;strong&gt;Create new entry&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can use the dummy contacts from &lt;code&gt;./data.ts&lt;/code&gt; in your &lt;code&gt;remix&lt;/code&gt; project and save them to the &lt;code&gt;Contact&lt;/code&gt; collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing CRUD Functionalities for Contact
&lt;/h2&gt;

&lt;p&gt;Now, we are going to use the &lt;code&gt;Contact&lt;/code&gt; collection as the data source for our Remix app.&lt;/p&gt;

&lt;p&gt;Before that, we need to expose the &lt;code&gt;Contact&lt;/code&gt; collection to the public API.&lt;/p&gt;

&lt;p&gt;In the Strapi dashboard, go to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; scroll to &lt;strong&gt;Users &amp;amp; Permissions Plugin&lt;/strong&gt; &amp;gt; select &lt;strong&gt;Roles&lt;/strong&gt; &amp;gt; &lt;strong&gt;Public&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the Permissions section, click on &lt;strong&gt;Contact&lt;/strong&gt; and &lt;strong&gt;Select all&lt;/strong&gt; permissions. &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%2Fi8cthp9zkxj2i6sco532.jpg" 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%2Fi8cthp9zkxj2i6sco532.jpg" alt="Contact collection permission.jpg" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will make your &lt;code&gt;Contact&lt;/code&gt; collection accessible for &lt;strong&gt;Create&lt;/strong&gt;, &lt;strong&gt;Read&lt;/strong&gt;, &lt;strong&gt;Update&lt;/strong&gt;, and &lt;strong&gt;Delete&lt;/strong&gt; (CRUD) operations via API endpoints .&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;http://localhost:1337/api/contacts&lt;/code&gt;. It will return your contact list in JSON format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "data": [
        {
            "id": 2,
            "documentId": "dva2ab16hv3bzq9s5onbxgvb",
            "first": "Shruti",
            "last": "Kapoor",
            "avatar": "https://sessionize.com/image/124e-400o400o2-wHVdAuNaxi8KJrgtN3ZKci.jpg",
            "twitter": "@shrutikapoor08",
            "notes": null,
            "favorite": null,
            "createdAt": "2024-12-12T08:21:21.633Z",
            "updatedAt": "2024-12-12T08:21:21.633Z",
            "publishedAt": "2024-12-12T08:21:21.657Z"
        },
        {
            "id": 4,
            "documentId": "y1s5z2oqmmppu1d9n7wmelc9",
            "first": "Ryan",
            "last": "Florence",
            "avatar": "https://sessionize.com/image/9273-400o400o2-3tyrUE3HjsCHJLU5aUJCja.jpg",
            "twitter": null,
            "notes": null,
            "favorite": true,
            "createdAt": "2024-12-12T08:21:41.582Z",
            "updatedAt": "2024-12-12T08:21:41.582Z",
            "publishedAt": "2024-12-12T08:21:41.587Z"
        },
        {
            "id": 6,
            "documentId": "fnpqe7u1pm70bkcx6yjzahq7",
            "first": "Oscar",
            "last": "Newman",
            "avatar": "https://sessionize.com/image/d14d-400o400o2-pyB229HyFPCnUcZhHf3kWS.png",
            "twitter": "@__oscarnewman",
            "notes": null,
            "favorite": null,
            "createdAt": "2024-12-12T08:22:03.956Z",
            "updatedAt": "2024-12-12T08:22:03.956Z",
            "publishedAt": "2024-12-12T08:22:03.961Z"
        },
        {
            "id": 11,
            "documentId": "n6yoo2mil4a36kpia4qy2x03",
            "first": "Muhammad",
            "last": "Syakirurohman",
            "avatar": "https://devaradise.com/_astro/syakir.JYhBotXK_1ltmJh.webp",
            "twitter": "@syakirurohman",
            "notes": null,
            "favorite": true,
            "createdAt": "2024-12-13T23:47:36.654Z",
            "updatedAt": "2024-12-13T23:58:48.752Z",
            "publishedAt": "2024-12-13T23:58:48.758Z"
        }
    ],
    "meta": {
        "pagination": {
            "page": 1,
            "pageSize": 25,
            "pageCount": 1,
            "total": 4
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fetching All Contacts from Strapi
&lt;/h3&gt;

&lt;p&gt;Previously, our data source for the contact list was dummy data stored as a variable in &lt;code&gt;data.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, we will refactor &lt;code&gt;data.ts&lt;/code&gt; to fetch the &lt;code&gt;Contact&lt;/code&gt; collection from Strapi.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rename &lt;code&gt;data.ts&lt;/code&gt; to &lt;code&gt;data.server.ts&lt;/code&gt;. This ensures it runs only on the server side. Make sure to update all import statements for &lt;code&gt;data.server&lt;/code&gt; in other files accordingly.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We add &lt;code&gt;documentId&lt;/code&gt; field to &lt;code&gt;ContactMutation&lt;/code&gt; type since every data from Strapi version 5 is automatically added this field. The &lt;code&gt;documentId&lt;/code&gt; will be used to get contact detail from Strapi.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Refactor the &lt;code&gt;data.server.ts&lt;/code&gt; by removing all code related to dummy data. Clear all function bodies and add a &lt;code&gt;STRAPI_BASE_URL&lt;/code&gt; variable to store the Strapi API base URL.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ContactMutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;first&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;last&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;favorite&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;type&lt;/span&gt; &lt;span class="nx"&gt;ContactRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ContactMutation&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STRAPI_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRAPI_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:1337&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getContacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createEmptyContact&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContactMutation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fetch all contacts from Strapi, let's redefine the &lt;code&gt;getContacts&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getContacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STRAPI_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/contacts&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;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ContactMutation&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, go to &lt;code&gt;root.tsx&lt;/code&gt;. Make sure you change the import source for &lt;code&gt;getContacts&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getContacts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./data.server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and reload your app homepage. You will see that now it fetch the contacts from Strapi.&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%2Fn2yadx49zxwlc9lj7bnz.jpg" 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%2Fn2yadx49zxwlc9lj7bnz.jpg" alt="Contact list from Strapi.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fetching Single Contact
&lt;/h3&gt;

&lt;p&gt;Since we have refactored &lt;code&gt;data.ts&lt;/code&gt;, the contact detail page is temporary not working. So, let's fix it so it gets the contact data from Strapi contact.&lt;/p&gt;

&lt;p&gt;Still in the &lt;code&gt;root.tsx&lt;/code&gt;, Scroll to the &lt;code&gt;nav&lt;/code&gt; tag where we iterate the &lt;code&gt;contacts&lt;/code&gt; variable, change the &lt;code&gt;${contact.id}&lt;/code&gt; to &lt;code&gt;${contact.documentId}&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="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;nav&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`contacts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
                  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&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;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;No Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favorite&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;★&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&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;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;No contacts&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will change the &lt;code&gt;contactId&lt;/code&gt; param in contact detail page.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code&gt;data.server.ts&lt;/code&gt; and redefine the &lt;code&gt;getContact&lt;/code&gt; function as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STRAPI_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/contacts/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;documentId&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;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;./routes/contacts.$contactId.tsx&lt;/code&gt;, make sure you change the import source for &lt;code&gt;getContact&lt;/code&gt; function to &lt;code&gt;./data.server&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getContacts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./data.server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and reload the app. Click on a contact in the contact list, and it should render the contact detail page with data fetched from Strapi.&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%2F3nykqzj01c07lj7vh0yh.jpg" 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%2F3nykqzj01c07lj7vh0yh.jpg" alt="Strapi contact detail page.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Contact Functionality
&lt;/h3&gt;

&lt;p&gt;Next, let's add the &lt;strong&gt;Create Contact&lt;/strong&gt; functionality.&lt;/p&gt;

&lt;p&gt;We already have a &lt;code&gt;New&lt;/code&gt; button beside the search field in the sidebar. Currently, clicking it returns a 405 error.&lt;/p&gt;

&lt;p&gt;Now, let's change this button to a link that redirects to the &lt;code&gt;create&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;root.tsx&lt;/code&gt;, locate the following code:&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="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;New&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change it to&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contacts/create"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"buttonLink"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this CSS style to &lt;code&gt;app.css&lt;/code&gt; to style the &lt;code&gt;Create&lt;/code&gt; link&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.buttonLink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inherit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt; &lt;span class="m"&gt;0.75rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0px&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#3992ff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&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;Now, let's create a new page component form Create contact page.&lt;/p&gt;

&lt;p&gt;Add new file in &lt;code&gt;routes&lt;/code&gt; folder &lt;code&gt;./routes/contacts.create.tsx&lt;/code&gt;. Copy and paste this Create form component.&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;useNavigate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CreateContact&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;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useNavigate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"create-form-grid"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt;
          &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"First name"&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"first"&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"First name"&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"First"&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt;
          &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Last name"&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"last"&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Last name"&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Last"&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"twitter"&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Twitter"&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@jack"&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt;
          &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Avatar URL"&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Avatar URL"&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/avatar.jpg"&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;br&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"input-field"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"notes"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Notes&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"notes"&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"notes"&lt;/span&gt; &lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button-group"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Cancel
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FormInput&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Readonly&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;type&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="nl"&gt;name&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;label&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;placeholder&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;errors&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;defaultValue&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;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"input-field"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"input-error"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&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;Add this CSS blocks to &lt;code&gt;./app.css&lt;/code&gt; as well for styling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.button-group&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.input-field&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.input-field&lt;/span&gt; &lt;span class="nt"&gt;textarea&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.input-error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#e53e3e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.create-form-grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.root-error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.contact-error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6rem&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;Save the filees, and navigate to Create contact page by clicking on &lt;code&gt;Create&lt;/code&gt; button.&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%2F9g1sfov8hfsh6elvr51k.jpg" 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%2F9g1sfov8hfsh6elvr51k.jpg" alt="Contact form component.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before proceeding further, let's understand how the Remix &lt;code&gt;&amp;lt;Form&amp;gt;&lt;/code&gt; component works.&lt;/p&gt;

&lt;p&gt;The native HTML &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; have at least two attributes: &lt;code&gt;action&lt;/code&gt; and &lt;code&gt;method&lt;/code&gt;. Upon submission, the form sends an HTTP request to the URL specified in the &lt;code&gt;action&lt;/code&gt; attribute using the HTTP method defined in the &lt;code&gt;method&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;action&lt;/code&gt; attribute is not defined, it will send the request to the same page.&lt;/p&gt;

&lt;p&gt;The Remix &lt;code&gt;&amp;lt;Form&amp;gt;&lt;/code&gt; component follows the same approach. Any Remix &lt;code&gt;route&lt;/code&gt; can have an &lt;code&gt;action&lt;/code&gt; function to handle the form request sent to that route.&lt;/p&gt;

&lt;p&gt;A Remix &lt;code&gt;action&lt;/code&gt; is a special function in your route file that manages data mutations, such as creating, updating, or deleting data, triggered by form submissions or specific server requests.&lt;/p&gt;

&lt;p&gt;Remember the &lt;code&gt;loader&lt;/code&gt; function we used to fetch data? The &lt;code&gt;action&lt;/code&gt; function is similar, but it is used for data mutation. It also has to be explicitly named &lt;code&gt;action&lt;/code&gt; in your route file.&lt;/p&gt;

&lt;p&gt;You also don't have to manually control the state of each field. Remix &lt;code&gt;&amp;lt;Form&amp;gt;&lt;/code&gt; uses the standard Web API (FormData) to handle forms. Just make sure that all form fields have &lt;code&gt;name&lt;/code&gt; attributes.&lt;/p&gt;

&lt;p&gt;Now, let's add the codes to handle the Contact form submission.&lt;/p&gt;

&lt;p&gt;First, go to the &lt;code&gt;data.server.ts&lt;/code&gt;. Change the &lt;code&gt;createEmptyContact&lt;/code&gt; function to &lt;code&gt;createContact&lt;/code&gt; and add the codes to add new record to Strapi Contact collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in ./data.server.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STRAPI_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/contacts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we use the same &lt;code&gt;fetch&lt;/code&gt; function to connect to the Strapi API. This time, we specify the "POST" method and include the data in the request body.&lt;/p&gt;

&lt;p&gt;Now, return to &lt;code&gt;./routes/contacts.create.tsx&lt;/code&gt; and add the &lt;code&gt;action&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useNavigate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;createContact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../data.server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&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;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&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;newEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/contacts/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;newEntry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentId&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CreateContact&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// nothing changed in this block for now&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we added the &lt;code&gt;action&lt;/code&gt; function for this route. Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The form submission data is captured in the &lt;code&gt;{ request }&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;createContact&lt;/code&gt; function is called to add a new record to the Strapi Contact collection using the submitted form data.&lt;/li&gt;
&lt;li&gt;If the contact creation is successful, it redirects to the detail page of the newly created contact using the &lt;code&gt;redirect&lt;/code&gt; function provided by Remix. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Save your changes and reload the app. Try adding new contact and see how it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Form validation with Zod and Remix
&lt;/h3&gt;

&lt;p&gt;Although we have added the Create contact functionality, it doesnt have the form validation. You still can input anything without check.&lt;/p&gt;

&lt;p&gt;Even if you submit a blank input, it will still create a new contact.&lt;/p&gt;

&lt;p&gt;So, in this section we will add form validation using Zod.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://zod.dev/" rel="noopener noreferrer"&gt;Zod&lt;/a&gt; is a TypeScript-first library for schema declaration and validation, offering a simple API to define, parse, and validate data structures with runtime type safety. It supports detailed error handling, and is ideal for validating inputs, APIs, and complex data in modern applications.&lt;/p&gt;

&lt;p&gt;Install Zod in your Remix project by running:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i zod&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Make sure you execute this command in the &lt;code&gt;remix&lt;/code&gt; folder via terminal.&lt;/p&gt;

&lt;p&gt;Next, import &lt;code&gt;zod&lt;/code&gt; into &lt;code&gt;contacts.create.tsx&lt;/code&gt; and define a schema within the &lt;code&gt;action&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useNavigate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;createContact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../data.server&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&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;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&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;formSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validatedFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;validatedFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;validatedFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;fieldErrors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please fill out all missing fields.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/contacts/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;newEntry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentId&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CreateContact&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// Nothing changed yet here&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We introduced the &lt;code&gt;formSchema&lt;/code&gt; variable, which defines the validation rules for each field in the Create contact form.&lt;/li&gt;
&lt;li&gt;We parse the input data from the Create contact form request using &lt;code&gt;formSchema.safeParse()&lt;/code&gt; and store the result in the &lt;code&gt;validateFields&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt;We added a conditional check: if &lt;code&gt;validateFields&lt;/code&gt; is unsuccessful, the action function returns an error object and halts the execution of the &lt;code&gt;createContact&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save your changes, and try adding a contact again with blank inputs.&lt;/p&gt;

&lt;p&gt;You will notice that it's not creating a new contact anymore. The form is actually returning errors from &lt;code&gt;zod&lt;/code&gt; validation.&lt;/p&gt;

&lt;p&gt;Now, let's show these error messages in our contact form.&lt;/p&gt;

&lt;p&gt;In the same file &lt;code&gt;contacts.create.tsx&lt;/code&gt;, within the the component function &lt;code&gt;CreateContact&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;useNavigate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useActionData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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;type&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;createContact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../data.server&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// nothing changed here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CreateContact&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;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useNavigate&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;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useActionData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"create-form-grid"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt;
          &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"First name"&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"first"&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"First name"&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"First"&lt;/span&gt;
          &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt;
          &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Last name"&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"last"&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Last name"&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Last"&lt;/span&gt;
          &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"twitter"&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Twitter"&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"@jack"&lt;/span&gt;
          &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FormInput&lt;/span&gt;
          &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Avatar URL"&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"avatar"&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Avatar URL"&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/avatar.jpg"&lt;/span&gt;
          &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;br&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"input-field"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"notes"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Notes&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;textarea&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"notes"&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"notes"&lt;/span&gt; &lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button-group"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Cancel
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We use &lt;code&gt;useActionData&lt;/code&gt; to fetch the form request result and assign it to the &lt;code&gt;formData&lt;/code&gt; variable. &lt;code&gt;useActionData&lt;/code&gt; is imported from &lt;code&gt;@remix-run/react&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We pass the &lt;code&gt;formData?.errors&lt;/code&gt; to the &lt;code&gt;FormInput&lt;/code&gt; component's &lt;code&gt;errors&lt;/code&gt; attribute. &lt;code&gt;FormInput&lt;/code&gt; will handle and display the error messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save your changes and try submitting blank inputs again in Create contact form. It will now showing the error messages.&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%2Ftzleum0ufnhqr6o7mlka.jpg" 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%2Ftzleum0ufnhqr6o7mlka.jpg" alt="Contact form error messages.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Contact Functionality
&lt;/h3&gt;

&lt;p&gt;In this section, we are going to add update contact functionality.&lt;/p&gt;

&lt;p&gt;First, let's create a new file in &lt;code&gt;/routes&lt;/code&gt; folder, named &lt;code&gt;contacts.$contactId_.edit.tsx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note the weird &lt;code&gt;_&lt;/code&gt; in &lt;code&gt;$contactId_&lt;/code&gt;. By default, routes will automatically nest inside routes with the same prefixed name. Adding a trailing &lt;code&gt;_&lt;/code&gt; tells the route to not nest inside &lt;code&gt;app/routes/contacts.$contactId.tsx&lt;/code&gt;. You can read more about this in the &lt;a href="https://remix.run/docs/en/main/file-conventions/routes" rel="noopener noreferrer"&gt;Route File Naming&lt;/a&gt; official docs.&lt;/p&gt;

&lt;p&gt;For the sake of brevity, we will use the same component and form validation we added in &lt;code&gt;contacts.create.tsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, copy all the codes in &lt;code&gt;contacts.create.tsx&lt;/code&gt; and paste it to &lt;code&gt;contacts.$contactId_.edit.tsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, make this changes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useNavigate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useActionData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;updateContact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getContact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./../data.server&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zod&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;invariant&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tiny-invariant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;invariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing contactId param&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;contact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contact&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;invariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing contactId param&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;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&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;formSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validatedFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;validatedFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;validatedFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;fieldErrors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please fill out all missing fields.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;updateContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/contacts/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;updatedEntry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentId&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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;EditContact&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;navigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useNavigate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useActionData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&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;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create-form-grid&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;FormInput&lt;/span&gt;
          &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;First name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;first&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;First name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;First&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormInput&lt;/span&gt;
          &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Last name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;last&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Last name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Last&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormInput&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;twitter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Twitter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@jack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormInput&lt;/span&gt;
          &lt;span class="nx"&gt;aria&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Avatar URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;avatar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Avatar URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/avatar.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;input-field&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;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Notes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;textarea&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button-group&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;button&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Update&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Cancel&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// nothing change in FormInput component&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FormInput&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;///...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We added a &lt;code&gt;loader&lt;/code&gt; function to load the existing contact, similar to the one in &lt;code&gt;contacts.$contactId.tsx&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;action&lt;/code&gt; function, we included &lt;code&gt;params&lt;/code&gt; in the arguments to fetch &lt;code&gt;params.contactId&lt;/code&gt;. This will be passed to the &lt;code&gt;updateContact&lt;/code&gt; function as an argument. &lt;/li&gt;
&lt;li&gt;We renamed the component to &lt;code&gt;EditContact&lt;/code&gt;. Using &lt;code&gt;useLoaderData&lt;/code&gt;, we accessed the loaded contact data and prefilled the contact fields in &lt;code&gt;&amp;lt;FormInput&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; by setting their &lt;code&gt;defaultValue&lt;/code&gt; attributes. &lt;/li&gt;
&lt;/ul&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%2F1ls1cck76y2eylubrc58.jpg" 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%2F1ls1cck76y2eylubrc58.jpg" alt="Edit contact page.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Update Contact page now renders a contact form with prefilled information. However, the update contact functionality is not working yet. &lt;/p&gt;

&lt;p&gt;We still need to implement the API call to Strapi in the &lt;code&gt;updateContact&lt;/code&gt; function within &lt;code&gt;./data.server.ts&lt;/code&gt;. Update the &lt;code&gt;updateContact&lt;/code&gt; function as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ContactMutation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STRAPI_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/contacts/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we use the same &lt;code&gt;fetch&lt;/code&gt; function to connect to the Strapi API. This time, we specify the "PUT" method and include the updated data in the request body.&lt;/p&gt;

&lt;p&gt;Save your code, and try updating a contact. It should be working now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implement Delete Contact Functionality
&lt;/h3&gt;

&lt;p&gt;As we have added create and update contact functionality, let's also implement the delete contact functionality.&lt;/p&gt;

&lt;p&gt;Earlier, in the contact detail page &lt;code&gt;contact.$contactId.tsx&lt;/code&gt;, we added a delete button wrapped in the Remix &lt;code&gt;&amp;lt;Form&amp;gt;&lt;/code&gt; component.&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"delete"&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;
    &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please confirm you want to delete this record.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon clicking the Delete button, it prompts a native browser alert to confirm your action. &lt;/p&gt;

&lt;p&gt;If you confirm, the form will submit a request to &lt;code&gt;/contacts/${documentId}/delete&lt;/code&gt;, as defined in the &lt;code&gt;action&lt;/code&gt; attribute, and throw a &lt;code&gt;405 error&lt;/code&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%2Ftuxx3ftu8gqyct9tcv1p.jpg" 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%2Ftuxx3ftu8gqyct9tcv1p.jpg" alt="Delete contact 405 error.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This happened because we haven't created a delete route yet to handle this request.&lt;/p&gt;

&lt;p&gt;Let us now create a new route file named &lt;code&gt;contacts.$contactId.delete.tsx&lt;/code&gt; inside &lt;code&gt;/routes&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;In Remix, we can have a route that only handles a request, without a UI. This is what we will do with the delete route.&lt;/p&gt;

&lt;p&gt;We only need to add an &lt;code&gt;action&lt;/code&gt; function to handle the delete request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;invariant&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tiny-invariant&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;deleteContact&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../data.server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;invariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing contactId param&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="nf"&gt;deleteContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/contacts&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;In the code above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We check the &lt;code&gt;params.contactId&lt;/code&gt; with invariant, as we also do in contact detail page and update contact action.&lt;/li&gt;
&lt;li&gt;We called &lt;code&gt;deleteContact&lt;/code&gt; from &lt;code&gt;./data.server&lt;/code&gt; to execute the delete contact functionality&lt;/li&gt;
&lt;li&gt;If deletion success we will redirect the page route to &lt;code&gt;/contacts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;code&gt;./data.server.ts&lt;/code&gt;, we also need to update the &lt;code&gt;deleteContact&lt;/code&gt; function as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STRAPI_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/contacts/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;documentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DELETE&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we call the Strapi endpoint &lt;code&gt;/api/contact/${documentId}&lt;/code&gt; with the &lt;code&gt;DELETE&lt;/code&gt; method to delete the contact with the corresponding &lt;code&gt;documentId&lt;/code&gt;. The &lt;code&gt;documentId&lt;/code&gt; matches the &lt;code&gt;contactId&lt;/code&gt; used in the URL.&lt;/p&gt;

&lt;p&gt;Save your code and try deleting a contact. If successful, you will be redirected to the &lt;code&gt;/contacts&lt;/code&gt; page.&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%2F8lkvypcysb1fq56ohlpg.jpg" 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%2F8lkvypcysb1fq56ohlpg.jpg" alt="Contacts not found.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice it shows a &lt;code&gt;404 Not Found&lt;/code&gt; error because we don't have a route page for &lt;code&gt;/contacts&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up Fallback page when no contact selected
&lt;/h3&gt;

&lt;p&gt;Let's add a simple component for the &lt;code&gt;/contacts&lt;/code&gt; route.&lt;/p&gt;

&lt;p&gt;Create a new file named &lt;code&gt;contacts_.tsx&lt;/code&gt; in the &lt;code&gt;/routes&lt;/code&gt; folder and paste this simple component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Contacts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;show&lt;/span&gt; &lt;span class="nx"&gt;up&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="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;Don't forget the &lt;code&gt;_&lt;/code&gt; in the &lt;code&gt;contacts_.tsx&lt;/code&gt; filename. It's necessary to prevent it from being rendered in its child routes (e.g., &lt;code&gt;/contacts/${contactId}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now, the &lt;code&gt;/contacts&lt;/code&gt; route should display like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcvzbfehcd66u5meoesx4.jpg" 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%2Fcvzbfehcd66u5meoesx4.jpg" alt="Contacts page.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Error in Remix
&lt;/h3&gt;

&lt;p&gt;In real-world applications, errors are inevitable, such as when a requested page is not found.&lt;/p&gt;

&lt;p&gt;By default, Remix provides a basic &lt;code&gt;404 Not Found&lt;/code&gt; error page to handle such scenarios.&lt;/p&gt;

&lt;p&gt;We can customize this error handling by creating and exporting a component named &lt;code&gt;ErrorBoundary&lt;/code&gt; in any route page where we want to manage errors.&lt;/p&gt;

&lt;p&gt;Let's try this by adding &lt;code&gt;ErrorBoundary&lt;/code&gt; component in &lt;code&gt;root.tsx&lt;/code&gt; to customize root error boundary.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ErrorBoundary&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;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouteError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Oh no!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Links&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Oh no! Something went wrong&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;isRouteErrorResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; Error&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;br&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"buttonLink"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Go back to home&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Scripts&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// nothing changed here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Dont forget to add &lt;code&gt;ErrorBoundary&lt;/code&gt; and &lt;code&gt;isRouteErrorResponse&lt;/code&gt; to the import code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isRouteErrorResponse&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;Links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Outlet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Scripts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ScrollRestoration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useRouteError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, save the file and try accessing the app with a random URL. The custom error boundary we just implemented will be displayed.&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%2F884oroy5mfp9p1vvcy6o.jpg" 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%2F884oroy5mfp9p1vvcy6o.jpg" alt="Custom error boundary for route.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apart from &lt;code&gt;root.tsx&lt;/code&gt;, we can also add a custom error boundary to any route.&lt;/p&gt;

&lt;p&gt;So, let's add an error boundary again to contact detail page.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;contacts.$contactId.tsx&lt;/code&gt;, add the following codes above the &lt;code&gt;Contact()&lt;/code&gt; component&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ErrorBoundary&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;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouteError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Oh no! Something went wrong&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;isRouteErrorResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; Error&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;br&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"buttonLink"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Go back to home&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&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;Dont forget to import &lt;code&gt;ErrorBoundary&lt;/code&gt; and &lt;code&gt;isRouteErrorResponse&lt;/code&gt; from &lt;code&gt;@remix-run/react&lt;/code&gt; as well, so the updated import code is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isRouteErrorResponse&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;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRouteError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;loader&lt;/code&gt; function in &lt;code&gt;contact.$contactId.tsx&lt;/code&gt;, there is an error thrown when the contact is not found in the Strapi API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;invariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing contactId param&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;contact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;"Not Found"&lt;/code&gt; text on line 8 in the code above will be passed to &lt;code&gt;error.data&lt;/code&gt; in the &lt;code&gt;ErrorBoundary&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Change &lt;code&gt;"Not Found"&lt;/code&gt; to &lt;code&gt;"Contact Not Found"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Save the file, then access a contact detail page using a &lt;code&gt;nonexistingid&lt;/code&gt;. The error page will now display as follows:&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%2Fql1vxkmcy6kg0kiud80o.jpg" 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%2Fql1vxkmcy6kg0kiud80o.jpg" alt="Contact not found error.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Mark Contact as Favorite
&lt;/h3&gt;

&lt;p&gt;In the contact detail page, &lt;code&gt;contact.$contactId.tsx&lt;/code&gt;, we have already included a &lt;code&gt;&amp;lt;Favorite&amp;gt;&lt;/code&gt; component.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Favorite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pick&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ContactRecord&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;favorite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;favorite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favorite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
        &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;favorite&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Remove from favorites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Add to favorites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"favorite"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;favorite&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;favorite&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;★&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;☆&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&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;The &lt;code&gt;&amp;lt;Favorite&amp;gt;&lt;/code&gt; component is functioning as a form. When you click the star icon, it sends a &lt;code&gt;POST&lt;/code&gt; request to the contact detail page. This request contains a &lt;code&gt;favorite&lt;/code&gt; field with a value of &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;, as specified in the button's &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; attributes.&lt;/p&gt;

&lt;p&gt;Currently, it does nothing because we haven't handled this request. To make it functional, we need to add an &lt;code&gt;action&lt;/code&gt; function to &lt;code&gt;contact.$contactId.tsx&lt;/code&gt; that updates the &lt;code&gt;favorite&lt;/code&gt; field of the contact.&lt;/p&gt;

&lt;p&gt;For this, we will reuse the same &lt;code&gt;updateContact&lt;/code&gt; function that we utilized in the Update Contact page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;invariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing contactId param&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;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;updateContact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contactId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;favorite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;favorite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&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="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dont forget to also import &lt;code&gt;ActionFunctionArgs&lt;/code&gt; and &lt;code&gt;updateContact&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// other imports&lt;/span&gt;
&lt;span class="c1"&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;getContact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateContact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ContactRecord&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../data.server&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ActionFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save your changes, and try to favorite or unfavorite the contact. You will see that now you can star or unstar a contact.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search Functionality
&lt;/h3&gt;

&lt;p&gt;The search form has been part of the UI since the beginning of this tutorial, but its functionality hasn't been implemented yet. &lt;/p&gt;

&lt;p&gt;Before we proceed to implement it, let’s take a closer look at the Strapi API used to fetch the contact list, specifically the &lt;code&gt;GET /api/contacts&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;If you access this endpoint in your browser locally at &lt;code&gt;http://localhost:1337/api/contacts&lt;/code&gt;, you will receive a JSON response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "data": [
        {
            "id": 34,
            "documentId": "y1s5z2oqmmppu1d9n7wmelc9",
            "first": "Ryan",
            "last": "Florence",
            "avatar": "https://sessionize.com/image/9273-400o400o2-3tyrUE3HjsCHJLU5aUJCja.jpg",
            "twitter": null,
            "notes": null,
            "favorite": false,
            "createdAt": "2024-12-12T08:21:41.582Z",
            "updatedAt": "2024-12-18T12:50:16.890Z",
            "publishedAt": "2024-12-18T12:50:16.896Z"
        },
       // ...other contacts
    ],
    "meta": {
        "pagination": {
            "page": 1,
            "pageSize": 25,
            "pageCount": 1,
            "total": 4
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end of the JSON response, you’ll notice a &lt;code&gt;meta&lt;/code&gt; field containing a &lt;code&gt;pagination&lt;/code&gt; object. &lt;/p&gt;

&lt;p&gt;By default, Strapi limits the response from collection list APIs, such as &lt;code&gt;GET /api/contacts&lt;/code&gt;, to a maximum of 25 rows, as indicated by the &lt;code&gt;pageSize&lt;/code&gt; property. Additionally, the results are sorted by the &lt;code&gt;updatedAt&lt;/code&gt; field in ascending order.&lt;/p&gt;

&lt;p&gt;If our contact list contains more than 25 rows, the sidebar won't display all the contacts. In real-world applications, this scenario is typically addressed by implementing pagination logic. &lt;/p&gt;

&lt;p&gt;For simplicity, we'll modify the API query to increase the &lt;code&gt;pageSize&lt;/code&gt; to 50. Additionally, we'll sort the contact list by the &lt;code&gt;createdAt&lt;/code&gt; field in descending order so that the newest contacts appear at the top of the list.&lt;/p&gt;

&lt;p&gt;After that, we will implement the search filter by keyword.&lt;/p&gt;

&lt;p&gt;All these functionalities will be achieved by passing query parameters to the Strapi endpoints, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/contacts?sort[0]=createdAt:desc&amp;amp;filters[first][$contains]=syakir&amp;amp;filters[last][$contains]=syakir&amp;amp;pagination[pageSize]=50&amp;amp;pagination[page]=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the URL is not human-readable. To simplify this process, we will use the &lt;a href="https://www.npmjs.com/package/qs" rel="noopener noreferrer"&gt;qs&lt;/a&gt; library to pass the query parameters in JSON format. The library will automatically build the query string in URL format based on the JSON object we provide.&lt;/p&gt;

&lt;p&gt;You can learn more about this in the Strapi &lt;a href="https://docs.strapi.io/dev-docs/api/rest/interactive-query-builder" rel="noopener noreferrer"&gt;interactive query builder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run the following command to install the &lt;code&gt;qs&lt;/code&gt; library in your Remix project. Make sure you're in the &lt;code&gt;remix&lt;/code&gt; folder in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i qs
npm i @types/qs &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to &lt;code&gt;./data.server.ts&lt;/code&gt;. In the top of file, import &lt;code&gt;qs&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;qs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, update &lt;code&gt;getContacts&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getContacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&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;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;qs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;createdAt:desc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;$or&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$contains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="p"&gt;}},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$contains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="p"&gt;}},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;$contains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="p"&gt;}},&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;pagination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STRAPI_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/contacts?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;query&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;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ContactMutation&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we implemented a query builder to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sort the contact list by the &lt;code&gt;createdAt&lt;/code&gt; column in descending order.&lt;/li&gt;
&lt;li&gt;Filter contacts based on keywords contained in the &lt;code&gt;first&lt;/code&gt;, &lt;code&gt;last&lt;/code&gt;, and &lt;code&gt;twitter&lt;/code&gt; fields. &lt;/li&gt;
&lt;li&gt;Set the pagination &lt;code&gt;pageSize&lt;/code&gt; to 50.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this stage, sorting by &lt;code&gt;createdAt&lt;/code&gt; and increasing rows limit per page to 50 is functional. You can test it by adding a new contact, which will appear at the top of the list.&lt;/p&gt;

&lt;p&gt;The search functionality, however, is not yet working. We still need to pass the search keyword from the search form to the &lt;code&gt;getContacts&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;./root.tsx&lt;/code&gt;. Update the codes as follows.&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;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isRouteErrorResponse&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;Links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Outlet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Scripts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ScrollRestoration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useRouteError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&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;LoaderFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;LinksFunction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/node&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;appStyleHref&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;./app.css?url&lt;/span&gt;&lt;span class="dl"&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;getContacts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./data.server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LinksFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stylesheet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appStyleHref&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;const&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;q&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;contacts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getContacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;q&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;ErrorBoundary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// nothing changed in error boundary&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSubmit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charSet&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Links&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sidebar"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Remix Contacts&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search-form"&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;
                &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Search contacts"&lt;/span&gt;
                &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Search"&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;
                &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search-spinner"&lt;/span&gt; &lt;span class="na"&gt;aria-hidden&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            // nothing changed after this code            
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        //... other codes
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  );
}

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

&lt;/div&gt;



&lt;p&gt;In the code above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;loader&lt;/code&gt; function was updated to extract the &lt;code&gt;?q=&lt;/code&gt; query parameter from the URL, which contains the search keyword from the search form, and assigns it to the &lt;code&gt;q&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;q&lt;/code&gt; variable was included in the return value so that it can be used to synchronize the search form field with the &lt;code&gt;q&lt;/code&gt; query parameter in the URL.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;useSubmit&lt;/code&gt; hook was used in the &lt;code&gt;App()&lt;/code&gt; component to handle submission from the search form. This hook was assigned to the &lt;code&gt;onChange&lt;/code&gt; event handler in the search form, enabling real-time submission of the search request when the search input changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, try the search input—it should work in real-time!&lt;/p&gt;

&lt;h3&gt;
  
  
  Add loading state to Search
&lt;/h3&gt;

&lt;p&gt;When user internet connection is slow, you'll notice that there will be some delay or lag in search funtionality. You can simulate this by changing the internet connection speed to 3G in &lt;strong&gt;Devtools&lt;/strong&gt; &amp;gt; &lt;strong&gt;Network Tab&lt;/strong&gt; in your browser&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%2F142tznmgrbz680bfnoms.jpg" 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%2F142tznmgrbz680bfnoms.jpg" alt="Internet connection speed.jpg" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To handle the waiting state for the Strapi API to respond, we'll add the loading state to search form.&lt;/p&gt;

&lt;p&gt;We will also refactor a bit on how we submit the search form request. Our search functionality is creating a lot of history stack because it &lt;code&gt;push&lt;/code&gt; a new route in every keystroke, when we submitted the form.&lt;/p&gt;

&lt;p&gt;So, we will use &lt;code&gt;replace&lt;/code&gt; method to solve this.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;root.tsx&lt;/code&gt;, update the &lt;code&gt;App&lt;/code&gt; component function.&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="c1"&gt;// add new import `useNavigation`&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;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;isRouteErrorResponse&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;Links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Outlet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Scripts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ScrollRestoration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useNavigation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useRouteError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//.. other imports&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// nothing changed here&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;ErrorBoundary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// nothing changed here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSubmit&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;navigation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useNavigation&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;searching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;q&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="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charSet&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Links&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sidebar"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Remix Contacts&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search-form"&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isFirstSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isFirstSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
                &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;
                &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searching&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loading&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="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Search contacts"&lt;/span&gt;
                &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Search"&lt;/span&gt; 
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;
                &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search-spinner"&lt;/span&gt; &lt;span class="na"&gt;aria-hidden&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;searching&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contacts/create"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"buttonLink"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          //... other codes, nothing changed here
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          //... other codes, nothing changed here
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&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;In the code above: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useNavigation&lt;/code&gt; was imported to access the navigation state, which will be used to evaluate a loading state.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;searching&lt;/code&gt; variable was declared to evaluate the presence of a query parameter and the navigation state. This variable is used to determine if the search is currently loading. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;onChange&lt;/code&gt; function for the search form was updated to ensure that the submit function replaces the existing browser history stack instead of pushing a new one with each keystroke. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;searching&lt;/code&gt; variable was applied to conditionally add a &lt;code&gt;loading&lt;/code&gt; class to the input field and to toggle the visibility of the search spinner. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save the changes and test the search feature again on a slow connection to observe the loading state in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Review and Challenges
&lt;/h2&gt;

&lt;p&gt;We have implemented a fully-functional contact app with Remix as Front-end and Strapi as backend. You can create, update, delete and search the contact data from strapi directly in our app.&lt;/p&gt;

&lt;p&gt;But, the project is far from perfect. There is always some room for improvement&lt;/p&gt;

&lt;p&gt;In a real-world app, you might want to optimize your app for better user experience. So, i want you to implement these challenges to optimize our contact app.&lt;/p&gt;

&lt;p&gt;The answer for these challenges are still included in project code in Github, but i want you to be more creative and solve the problem on your own.&lt;/p&gt;

&lt;p&gt;I will provide some hints and related links to the official remix documentation&lt;/p&gt;

&lt;h3&gt;
  
  
  Implement debounce in search functionality
&lt;/h3&gt;

&lt;p&gt;In the current search contact functionality, the app makes an API call to Strapi each time the user types a letter in the search input. For instance, when searching for the name &lt;code&gt;Jane&lt;/code&gt;, the app will actually search for &lt;code&gt;J&lt;/code&gt;, &lt;code&gt;Ja&lt;/code&gt;, &lt;code&gt;Jan&lt;/code&gt;, and &lt;code&gt;Jane&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In a real-world application, this behavior can lead to unnecessary operations and resource wastage.&lt;/p&gt;

&lt;p&gt;Your task is to optimize this by ensuring the search form only hits the Strapi API endpoint after the user stops typing in the search input, rather than on every keystroke.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refactor the search form's &lt;code&gt;onChange&lt;/code&gt; function to implement a JavaScript debounce mechanism.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Highlight Selected Contact in sidebar
&lt;/h3&gt;

&lt;p&gt;When a contact is selected and the contact detail page is opened, the sidebar contact list does not indicate which contact is currently selected.&lt;/p&gt;

&lt;p&gt;Your task is to highlight the selected contact. We already have the &lt;code&gt;active&lt;/code&gt; class for the selected contact link and the &lt;code&gt;pending&lt;/code&gt; class for transitions. Apply these two classes conditionally to the contact link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the Remix &lt;a href="https://remix.run/docs/en/main/components/nav-link" rel="noopener noreferrer"&gt;NavLink&lt;/a&gt; component to access the &lt;code&gt;active&lt;/code&gt; and &lt;code&gt;pending&lt;/code&gt; states.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using useFetcher for Favorite / Unfavorite Contact
&lt;/h3&gt;

&lt;p&gt;Currently, when you click to favorite or unfavorite a contact, the app performs a form submission and refreshes the page.&lt;/p&gt;

&lt;p&gt;Your task is to prevent the page from reloading or submitting the form natively by using Remix's &lt;code&gt;useFetcher&lt;/code&gt; in the favorite form component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://remix.run/docs/en/main/hooks/use-fetcher" rel="noopener noreferrer"&gt;useFetcher documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Handling Error from Backend
&lt;/h3&gt;

&lt;p&gt;We are already handling errors using the &lt;code&gt;ErrorBoundary&lt;/code&gt; component. However, the error messages and statuses are either default Remix messages or those defined in the &lt;code&gt;action&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Your task is to handle errors originating from Strapi and display the Strapi error message in the &lt;code&gt;ErrorBoundary&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Throw the error inside the &lt;code&gt;catch&lt;/code&gt; block in the function located in &lt;code&gt;./data/server&lt;/code&gt;. Include the Strapi error message in your error object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Link:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://remix.run/docs/en/main/guides/errors" rel="noopener noreferrer"&gt;Remix Error Handling Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project codes
&lt;/h2&gt;

&lt;p&gt;You can find complete project codes in this link: &lt;a href="https://github.com/syakirurahman/remix-strapi" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;We have successfully built a fully functional contact management app using Remix for the front end and Strapi headless CMS as the backend. The app enables users to create, update, delete, and search data in real-time, providing a solid foundation for your future project. &lt;/p&gt;

&lt;p&gt;Throughout the development process, we implemented Remix key features such as dynamic route handling, state management, error boundaries, and API integration.&lt;/p&gt;

&lt;p&gt;Next, you should keep practicing what you have learn here by creating your own project, and improvise it. Make the official documentation your friend.&lt;/p&gt;

&lt;p&gt;Follow the &lt;a href="https://strapi.io/blog" rel="noopener noreferrer"&gt;Strapi blog&lt;/a&gt; for more exciting tutorials and blog posts like this&lt;/p&gt;



</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>beginners</category>
    </item>
    <item>
      <title>11+ Best Open-source Web Analytics, Alternatives to Google Analytics 🚀</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Mon, 18 Nov 2024 11:44:39 +0000</pubDate>
      <link>https://dev.to/syakirurahman/11-best-open-source-web-analytics-alternatives-to-google-analytics-opj</link>
      <guid>https://dev.to/syakirurahman/11-best-open-source-web-analytics-alternatives-to-google-analytics-opj</guid>
      <description>&lt;p&gt;Hi Guys, &lt;/p&gt;

&lt;p&gt;Today i'm going to start a listicle series of open source tools alternatives to popular software.&lt;/p&gt;

&lt;p&gt;The list is basically a mirror of my new website &lt;a href="https://alternateoss.com" rel="noopener noreferrer"&gt;AlternateOSS&lt;/a&gt;. It's a directory of open source alternatives to popular software.&lt;/p&gt;

&lt;p&gt;Today, i will share about Web analytics tools, alternatives to google analytics. The original list is here &lt;a href="https://alternateoss.com/category/web-analytics/open-source/" rel="noopener noreferrer"&gt;https://alternateoss.com/category/web-analytics/open-source/&lt;/a&gt;. You can explore the tools there for better navigation 🌟&lt;/p&gt;




&lt;p&gt;Web Analytics focuses on tracking and analyzing website visitor behavior, including page views, traffic sources, user flows, and conversion metrics. It helps businesses understand how users interact with their website, optimize user experience, and improve marketing performance through tools like Google Analytics.&lt;/p&gt;

&lt;p&gt;The list below is a curated list of open source only web analytics tools, ranked based on relevancy and feature completeness as a web analytics tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Matomo
&lt;/h3&gt;

&lt;p&gt;Take control of your website's analytics with a powerful platform that ensures complete data ownership and respects user privacy without compromise&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%2Falternateoss.com%2F_astro%2Fmatomo-cover.BaJw1XFi.webp" 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%2Falternateoss.com%2F_astro%2Fmatomo-cover.BaJw1XFi.webp" alt="Comprehensive web analytics that prioritize data ownership and user privacy" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Matomo is a robust web analytics solution designed to give users full control over their data while providing insightful analytics. Unlike traditional platforms, Matomo allows for 100% data ownership, ensuring that all user interactions and metrics are stored securely and privately. Its user-friendly interface simplifies navigation, making it easy for anyone to access the information they need to enhance website performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Matomo is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;E-commerce Websites: Ideal for online stores needing detailed insights into customer behavior.&lt;/li&gt;
&lt;li&gt;Privacy-Conscious Organizations: Suitable for businesses that prioritize ethical data practices.&lt;/li&gt;
&lt;li&gt;Content Publishers: Great for blogs and news sites looking to track audience engagement effectively.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/matomo-org/matomo" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 19.9k stars)&lt;/a&gt;
 &lt;a href="https://matomo.org/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Plausible
&lt;/h3&gt;

&lt;p&gt;Experience a seamless transition to user-friendly analytics that respect privacy rights while delivering essential insights for your website&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%2Falternateoss.com%2F_astro%2Fplausible-cover.B0lwFVg0.webp" 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%2Falternateoss.com%2F_astro%2Fplausible-cover.B0lwFVg0.webp" alt="Privacy-centric web analytics that simplify data tracking and reporting" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Plausible is a lightweight and open-source web analytics tool designed to provide clear insights without compromising user privacy. With a focus on simplicity, it allows users to monitor site traffic and key metrics on a single page, eliminating the clutter often associated with traditional analytics platforms. Its cookie-free approach ensures compliance with privacy regulations such as GDPR and CCPA, making it an ideal choice for those prioritizing data protection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plausible is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Small Business Websites: Perfect for small enterprises needing straightforward analytics without complexity.&lt;/li&gt;
&lt;li&gt;Privacy-Conscious Organizations: Ideal for businesses that prioritize user privacy in their data collection practices.&lt;/li&gt;
&lt;li&gt;Marketing Campaign Analysis: Useful for tracking the effectiveness of various marketing initiatives through UTM parameters.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/plausible/analytics" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 20.5k stars)&lt;/a&gt;
 &lt;a href="https://plausible.io/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Umami
&lt;/h3&gt;

&lt;p&gt;Collect and analyze your website data effortlessly while ensuring compliance with privacy laws and maintaining user anonymity&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%2Falternateoss.com%2F_astro%2Fumami-cover.DGiTDlHh.webp" 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%2Falternateoss.com%2F_astro%2Fumami-cover.DGiTDlHh.webp" alt="Streamlined web analytics that prioritize privacy and data ownership" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Umami is a straightforward web analytics platform designed to simplify the process of collecting and interpreting web data. It focuses on essential metrics, allowing users to gain insights without the complexity of traditional analytics tools. By prioritizing visitor privacy, Umami ensures that all collected data is anonymized, making it impossible to identify individual users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Umami is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Small Business Analytics: Ideal for small businesses needing simple yet effective web tracking.&lt;/li&gt;
&lt;li&gt;Privacy-Conscious Websites: Suitable for organizations prioritizing user privacy in their data practices.&lt;/li&gt;
&lt;li&gt;Self-Hosted Solutions: Great for tech-savvy users looking to maintain full control over their analytics.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/umami-software/umami" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 22.9k stars)&lt;/a&gt;
 &lt;a href="https://umami.is/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Fathom Analytics
&lt;/h3&gt;

&lt;p&gt;Experience insightful analytics that prioritize user privacy and ease of use without the complexity of traditional tools&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%2Falternateoss.com%2F_astro%2Ffathom-cover.O6hg3DBF.webp" 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%2Falternateoss.com%2F_astro%2Ffathom-cover.O6hg3DBF.webp" alt="A simple, privacy-focused alternative to traditional web analytics" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fathom provides a straightforward analytics solution that simplifies tracking website performance while ensuring user privacy. It allows users to set up a single line of code on their website, enabling real-time data collection without the need for extensive technical knowledge. The platform blocks bots and spam traffic, ensuring that only genuine visitor data is captured, which enhances the accuracy of insights.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fathom Analytics is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Website performance analysis: Monitor traffic and user behavior on websites.&lt;/li&gt;
&lt;li&gt;Campaign tracking: Measure the effectiveness of marketing campaigns.&lt;/li&gt;
&lt;li&gt;User interaction insights: Understand how users engage with site elements.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/usefathom/fathom" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 7.7k stars)&lt;/a&gt;
 &lt;a href="https://usefathom.com/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Openpanel
&lt;/h3&gt;

&lt;p&gt;Experience a new standard in data analytics with a solution that prioritizes clarity, affordability, and user privacy while delivering comprehensive insights&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%2Falternateoss.com%2F_astro%2Fopenpanel-cover.WXBdVu1n.webp" 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%2Falternateoss.com%2F_astro%2Fopenpanel-cover.WXBdVu1n.webp" alt="An intuitive analytics platform that combines powerful features with user-friendly design" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Openpanel is an innovative analytics platform designed to provide users with a seamless experience in tracking and understanding their data. By merging the robust capabilities of Mixpanel with the simplicity of Plausible, it offers a unique approach to analytics that emphasizes ease of use without sacrificing depth. Users can access real-time event tracking, allowing them to monitor user interactions as they happen and gain immediate insights into their applications or websites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Openpanel is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Startups and Small Businesses: Ideal for teams needing an affordable yet powerful analytics solution.&lt;/li&gt;
&lt;li&gt;Mobile App Development: Perfect for developers looking to integrate analytics into their React Native apps.&lt;/li&gt;
&lt;li&gt;Data-Driven Decision Making: Great for organizations aiming to leverage user insights for strategic improvements.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics,Product Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Openpanel-dev/openpanel" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 3.1k stars)&lt;/a&gt;
 &lt;a href="https://openpanel.dev/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Open Web Analytics
&lt;/h3&gt;

&lt;p&gt;Gain insights into how visitors engage with your websites and applications while maintaining complete control over your data&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Falternateoss.com%2F_astro%2Fopen-web-analytics-cover.9xkHHi0j.webp" 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%2Falternateoss.com%2F_astro%2Fopen-web-analytics-cover.9xkHHi0j.webp" alt="Open-source web analytics framework that empowers you to control and analyze user interactions" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open Web Analytics (OWA) is a free, open-source web analytics tool that enables users to track and analyze visitor behavior on their websites and applications. Designed for flexibility, OWA allows you to run the software under your own domain, ensuring that you maintain full ownership of your data. Its customizable framework makes it easy to adapt the tool to meet specific analytical needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open Web Analytics is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Website Performance Tracking: Ideal for businesses needing detailed insights into user behavior.&lt;/li&gt;
&lt;li&gt;Custom Analytics Solutions: Perfect for developers looking to tailor analytics to specific requirements.&lt;/li&gt;
&lt;li&gt;Privacy-Conscious Organizations: Suitable for those prioritizing data protection and compliance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Open-Web-Analytics/Open-Web-Analytics" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 2.5k stars)&lt;/a&gt;
 &lt;a href="https://www.openwebanalytics.com/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Ackee
&lt;/h3&gt;

&lt;p&gt;Experience a powerful, privacy-focused analytics solution that runs on your own server, ensuring complete control over your data&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Falternateoss.com%2F_astro%2Fackee-cover.DjguZz4p.webp" 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%2Falternateoss.com%2F_astro%2Fackee-cover.DjguZz4p.webp" alt="A self-hosted analytics tool that prioritizes user privacy" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ackee is an open-source analytics platform designed for users who value privacy and simplicity. It operates on your own server, allowing you to track website traffic without the use of cookies or unique user identifiers, thereby ensuring data anonymization. The interface is minimalistic and user-friendly, providing essential insights like views, referrers, and visit durations without overwhelming users with unnecessary complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ackee is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Website traffic analysis: Monitor visitor behavior and engagement on personal or business websites.&lt;/li&gt;
&lt;li&gt;Privacy-conscious analytics: For organizations that prioritize user privacy in their data collection practices.&lt;/li&gt;
&lt;li&gt;Multi-domain management: Track performance across multiple sites or applications seamlessly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/electerious/Ackee" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 4.3k stars)&lt;/a&gt;
 &lt;a href="https://ackee.electerious.com/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Pirsch
&lt;/h3&gt;

&lt;p&gt;Discover a cookie-free, privacy-focused analytics solution designed to provide valuable insights while ensuring compliance with data protection regulations&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%2Falternateoss.com%2F_astro%2Fpirsch-cover.BubjZVNc.webp" 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%2Falternateoss.com%2F_astro%2Fpirsch-cover.BubjZVNc.webp" alt="A powerful analytics tool that respects user privacy" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pirsch is a web analytics platform that allows users to track website performance without the use of cookies or personal data collection. It offers a straightforward setup process, enabling users to integrate it into their sites quickly with minimal technical expertise. The platform is designed with privacy at its core, ensuring compliance with GDPR, CCPA, and other regulations while providing real-time data on user interactions and website performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pirsch is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Website performance monitoring: Analyze traffic patterns and user behavior on websites.&lt;/li&gt;
&lt;li&gt;Privacy-focused analytics: For organizations prioritizing compliance with data protection laws.&lt;/li&gt;
&lt;li&gt;Collaborative analytics management: Enable teams to work together on data insights efficiently.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/pirsch-analytics/pirsch" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 921 stars)&lt;/a&gt;
 &lt;a href="https://pirsch.io/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Litlyx
&lt;/h3&gt;

&lt;p&gt;Unlock powerful insights into user behavior and website performance while ensuring compliance with data protection regulations&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%2Falternateoss.com%2F_astro%2Flitlyx-cover.B3bQxvUA.webp" 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%2Falternateoss.com%2F_astro%2Flitlyx-cover.B3bQxvUA.webp" alt="A cookie-less analytics solution designed for modern privacy needs" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Litlyx is a cutting-edge analytics platform that prioritizes user privacy by offering cookie-less tracking and full GDPR compliance. With a simple setup that requires only a few lines of code, users can quickly start monitoring web analytics, conversion funnels, and custom events without the complexity often associated with traditional tools. The platform is designed for developers and marketers alike, providing robust cybersecurity measures and AI-driven insights to enhance decision-making.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Litlyx is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Web performance tracking: Monitor and analyze website traffic and user behavior.&lt;/li&gt;
&lt;li&gt;Conversion optimization: Identify and enhance conversion funnels for better results.&lt;/li&gt;
&lt;li&gt;Privacy-focused analytics: For organizations committed to protecting user data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Litlyx/litlyx" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 768 stars)&lt;/a&gt;
 &lt;a href="https://litlyx.com/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Offen
&lt;/h3&gt;

&lt;p&gt;Experience insightful web analytics that prioritize user privacy and compliance while providing actionable data for decision-making&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%2Falternateoss.com%2F_astro%2Foffen-cover.QspugIYn.webp" 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%2Falternateoss.com%2F_astro%2Foffen-cover.QspugIYn.webp" alt="A privacy-first analytics platform for data-conscious businesses" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Offen is an innovative analytics tool designed to help businesses track user interactions without compromising privacy. By utilizing a cookie-less approach, it ensures compliance with regulations like GDPR while offering a clear and intuitive interface for monitoring website performance. Users can quickly set up tracking with minimal technical knowledge, enabling them to focus on analyzing data rather than managing complex configurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offen is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Website performance monitoring: Analyze user behavior and traffic patterns effectively.&lt;/li&gt;
&lt;li&gt;Privacy-centric analytics: Ideal for organizations focusing on user data protection.&lt;/li&gt;
&lt;li&gt;Collaborative data analysis: Enable teams to work together on insights and strategies.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/offen/offen" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 877 stars)&lt;/a&gt;
 &lt;a href="https://offen.com/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  11. Posthog
&lt;/h3&gt;

&lt;p&gt;Unlock insights and enhance your product development with a comprehensive suite of analytics tools designed to empower teams in understanding user behavior and driving growth&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%2Falternateoss.com%2F_astro%2Fposthog-cover.LRoCSf6S.webp" 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%2Falternateoss.com%2F_astro%2Fposthog-cover.LRoCSf6S.webp" alt="The single platform for analyzing, testing, and deploying features efficiently" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PostHog is a powerful platform designed for product analytics, enabling teams to analyze user behavior through features like funnels, session replays, and retention tracking. It provides a cohesive environment for capturing and interpreting data, allowing businesses to make informed decisions based on user interactions and trends. With its open-source foundation, PostHog offers flexibility and adaptability for various product needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Posthog is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Startup Growth: Ideal for early-stage companies needing robust analytics without high costs.&lt;/li&gt;
&lt;li&gt;Feature Development: Use feature flags to test new functionalities safely.&lt;/li&gt;
&lt;li&gt;User Feedback Collection: Conduct in-app surveys to understand user needs better.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Product Analytics, Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/PostHog/posthog" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 22.0k stars)&lt;/a&gt;
 &lt;a href="https://posthog.com/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  12. Countly
&lt;/h3&gt;

&lt;p&gt;Unlock valuable insights into user behavior across your digital products while ensuring data privacy and compliance with regulations&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%2Falternateoss.com%2F_astro%2Fcountly-cover.CJsI2cCm.webp" 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%2Falternateoss.com%2F_astro%2Fcountly-cover.CJsI2cCm.webp" alt="A comprehensive product analytics platform that emphasizes user privacy and engagement" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Countly is a versatile product analytics solution designed to track and analyze user interactions across mobile, web, and desktop applications. By providing detailed insights into user journeys, Countly helps businesses understand how users engage with their products from acquisition to advocacy. Its privacy-centric approach ensures that all data is collected ethically, allowing organizations to comply with regulations such as GDPR while still gaining actionable insights.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Countly is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User Engagement Strategies: Useful for marketing teams looking to enhance user retention through targeted notifications.&lt;/li&gt;
&lt;li&gt;Mobile App Development: Ideal for developers seeking detailed insights into app performance and user engagement.&lt;/li&gt;
&lt;li&gt;Product Improvement Initiatives: Great for product managers aiming to prioritize features based on user feedback and behavior.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Product Analytics, Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Countly/countly-server" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 5.6k stars)&lt;/a&gt;
 &lt;a href="https://countly.com/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Aptabase
&lt;/h3&gt;

&lt;p&gt;Aptabase offers seamless data collection and insightful analytics while ensuring complete user anonymity and compliance with privacy regulations&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%2Falternateoss.com%2F_astro%2Faptabase-cover.CZe6-fxO.webp" 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%2Falternateoss.com%2F_astro%2Faptabase-cover.CZe6-fxO.webp" alt="A Privacy-focused analytics solution designed to simplify user tracking without legal complications" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aptabase is an innovative analytics platform that provides an open-source alternative to traditional tracking tools like Google Firebase Analytics. It enables developers to implement analytics quickly, creating a visually appealing dashboard in seconds. By focusing on anonymized data collection, Aptabase enhances privacy and reduces compliance burdens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aptabase is best used for&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mobile App Development: Ideal for developers seeking simple yet effective analytics solutions.&lt;/li&gt;
&lt;li&gt;Privacy-Conscious Projects: Perfect for organizations prioritizing user data protection.&lt;/li&gt;
&lt;li&gt;Startup Growth: Suitable for startups needing scalable analytics without upfront costs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Category&lt;/strong&gt;: Product Analytics, Web Analytics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aptabase/aptabase" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Github (⭐ 959 stars)&lt;/a&gt;
 &lt;a href="https://aptabase.com/?ref=alternateoss.com" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Home page 📑&lt;/a&gt;
&lt;/p&gt;




&lt;p&gt;Do you know other open source web analytics tools worth mentioning here? Don't hesitate to submit it in the comment. I might also list it to AlternateOSS for free.&lt;/p&gt;

&lt;p&gt;Thanks. Hope the list helps. Stay tune next week 🚀&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>analytics</category>
    </item>
    <item>
      <title>I Built AlternateOSS, A Directory of Free, Open-source Alternatives to Popular Software 🚀🔥</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Wed, 06 Nov 2024 14:12:07 +0000</pubDate>
      <link>https://dev.to/syakirurahman/i-built-alternateoss-a-directory-of-free-open-source-alternatives-to-popular-software-279c</link>
      <guid>https://dev.to/syakirurahman/i-built-alternateoss-a-directory-of-free-open-source-alternatives-to-popular-software-279c</guid>
      <description>&lt;p&gt;Hey guys 👋, Syakir here!&lt;/p&gt;

&lt;p&gt;Its been a while since my last post. I skipped my weekly blog posts because i have been busy working on a new project since a couple weeks ago. And now i want to share it with you.&lt;/p&gt;

&lt;p&gt;I'm currently building &lt;strong&gt;&lt;a href="https://alternateoss.com" rel="noopener noreferrer"&gt;AlternateOSS&lt;/a&gt;&lt;/strong&gt;, a website directory that sharing free, open-source alternatives to popular softwares.&lt;/p&gt;

&lt;p&gt;I am interested in the open source world, and started looking for open source alternatives for the tools i have used. Then, im thinking about creating directory for someone like me. I found similar existing projects on the internet, but i want to do it in more organized, and relevancy-oriented list.&lt;/p&gt;

&lt;p&gt;I collected 100+ softwares so far and share them with category organization.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stacks
&lt;/h2&gt;

&lt;p&gt;The stacks i used are simple. For now, it's fully static. I might convert them full-stack project later when the project become too big.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Astro&lt;/li&gt;
&lt;li&gt;✅ TailwindCSS&lt;/li&gt;
&lt;li&gt;✅ Shadcn / Radix&lt;/li&gt;
&lt;li&gt;✅ Markdown&lt;/li&gt;
&lt;li&gt;✅ Fully-static, NO Database&lt;/li&gt;
&lt;li&gt;✅ Cloudflare pages&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Highlighted Features
&lt;/h2&gt;

&lt;p&gt;Some hightlighted features that i think its cool, and you might interested to implement them to your project as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Smooth Navigation with View Transition
&lt;/h3&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%2Fcj4z2xd48th94x8q1fzg.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcj4z2xd48th94x8q1fzg.gif" alt="View Transition" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The View Transition API enables smooth animated transitions between pages/states in web applications.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It captures the "before" and "after" states of elements&lt;/li&gt;
&lt;li&gt;Automatically creates animations between these states&lt;/li&gt;
&lt;li&gt;Works with both same-origin navigations and DOM updates&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It makes the website really smooth. If it implemented in static website, it feel like it has no loading at all. &lt;/p&gt;

&lt;p&gt;I implemented it easily with &lt;a href="https://docs.astro.build/en/guides/view-transitions/" rel="noopener noreferrer"&gt;Astro View Transition&lt;/a&gt;. I just need to add a &lt;code&gt;&amp;lt;ViewTransition /&amp;gt;&lt;/code&gt; tag and &lt;code&gt;transition:name&lt;/code&gt; directives in every element i want to animate.&lt;/p&gt;

&lt;p&gt;*Note that the View Transition API is only working on Chromium based browsers. It currently not supported by Firefox.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static, Instant Search
&lt;/h3&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%2Fnz2a7t0gd0fegfj2q41x.jpg" 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%2Fnz2a7t0gd0fegfj2q41x.jpg" alt="Static Instant Search" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I build a fully static instant search with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Astro Static Endpoint&lt;/strong&gt;, where i store all search data in formatted json array: &lt;a href="https://alternateoss.com/api/search.json" rel="noopener noreferrer"&gt;https://alternateoss.com/api/search.json&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LocalStorage&lt;/strong&gt;, the search.json will only loaded once, and then stored to local storage, until the new version is available. From there, i simple use javascript array &lt;code&gt;.filter&lt;/code&gt; method for search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://cmdk.paco.me/" rel="noopener noreferrer"&gt;cmdk&lt;/a&gt; &amp;amp; &lt;a href="https://ui.shadcn.com/docs/components/command" rel="noopener noreferrer"&gt;Shadcn Command&lt;/a&gt;&lt;/strong&gt; for search input UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, This static instant search feature is not scalable. But, with the help of ChatGPT, i calculated that this method will still reliable until i reach 10k rows in search.json, with file size around 2MD. &lt;/p&gt;

&lt;p&gt;It will takes years to reach that number if i just input the softwares manually&lt;/p&gt;

&lt;h3&gt;
  
  
  Ranked Alternatives Based on Relevancy &amp;amp; Feature completeness
&lt;/h3&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%2F8h3r6qevpx39fwy4u9k6.jpg" 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%2F8h3r6qevpx39fwy4u9k6.jpg" alt="Ranked alternative list" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last, but not least. This might be the important feature that distinguish AlternateOSS with other similar project. I ranked every tools not based on its github stars or popularity, but mainly based on use cases / category relevancy and manual review for feature completeness / tool quality.&lt;/p&gt;

&lt;p&gt;For instance, we have some Google Analytics alternatives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Posthog: Category -&amp;gt; Product Analytics, Web analytics&lt;/li&gt;
&lt;li&gt;Umami: Category -&amp;gt; Web analytics&lt;/li&gt;
&lt;li&gt;Plausible: Category -&amp;gt; Web analytics&lt;/li&gt;
&lt;li&gt;Matomo: Category -&amp;gt; Web analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google analytics itself fall under 'Web analytics' category.&lt;br&gt;
The alternatives rank will put the main tools with main category &lt;code&gt;Web Analytics&lt;/code&gt; first before other categories.&lt;/p&gt;

&lt;p&gt;So, in this case, Posthog will rank lower even though it has more complete features than other tools in the list. While Umami, Plausible, and Matomo will be ranked based on manual review by myself.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What do you think about this project?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have any feedback, please dont hesitate to put it in the comment below.&lt;/p&gt;

&lt;p&gt;Thanks, happy coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>astro</category>
    </item>
    <item>
      <title>7 Best SaaS Boilerplates to Lauch Your SaaS Startup Faster 🚀</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Thu, 03 Oct 2024 10:28:20 +0000</pubDate>
      <link>https://dev.to/syakirurahman/7-best-saas-boilerplates-to-lauch-your-saas-startup-faster-47k2</link>
      <guid>https://dev.to/syakirurahman/7-best-saas-boilerplates-to-lauch-your-saas-startup-faster-47k2</guid>
      <description>&lt;p&gt;&lt;strong&gt;Checkout the &lt;a href="https://devaradise.com/best-saas-boilerplates/" rel="noopener noreferrer"&gt;original page&lt;/a&gt; to sort the boilerplate based rating, popularity &amp;amp; price ✨&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi there 👋. I'm Syakir, a Front-end engineer.&lt;/p&gt;

&lt;p&gt;In this page, i curated premium SaaS boilerplates from various vendors with top features and design to help you choose the right template for your Saas startup.&lt;/p&gt;

&lt;p&gt;I browsed and researched these boilerplates, then summarize what they offer, what stacks do they use, and rate them so you can quickly decide your choice.&lt;/p&gt;

&lt;p&gt;Each rating is my personal opinion after went through all of them. I rated them based the feature completeness, unique features, developer friendly (based on docs) and overall design.&lt;/p&gt;

&lt;p&gt;The links in this list are affiliate links, meaning that I may earn a small commission at no extra cost to you. This supports my work in providing curated resources like this one.&lt;/p&gt;

&lt;p&gt;I hope this list helps and save your time to research them.&lt;/p&gt;

&lt;p&gt;Cheers 🥂.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Supastarter By &lt;a href="https://x.com/jonathan_wilke" rel="noopener noreferrer"&gt;Jonathan Wilke&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsupastarter.DT_s_6se.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsupastarter.DT_s_6se.webp" alt="Supastarter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💲 &lt;strong&gt;Price:&lt;/strong&gt; $299 , ⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.87/5 (Editor rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Feature rich, multi-stack starterkit: Next.js, Nuxt &amp;amp; SvelteKit&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Supastarter setup: Landing Page, Blog, Docs, Analytics, Newsletter, Auth, Dashboard, Payments, Transaction Emails, Multilanguage, Multitenancy, Database + ORM, and AI Adapter for your SaaS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unique features: Multitenancy, AI Adapter&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multiple stack options for each feature&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exclusive discord server for support, updates and community&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monorepo &amp;amp; Modular architecture allows you to easily add and remove features&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://supastarter.dev/?aff=GLLjO" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Get it here 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Saasrock By &lt;a href="https://x.com/AlexandroMtzG" rel="noopener noreferrer"&gt;Alexandro Martinez&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsaasrock.DxU0n3rC.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsaasrock.DxU0n3rC.webp" alt="Saasrock"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💲 &lt;strong&gt;Price:&lt;/strong&gt; $149 , ⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.85/5 (Editor rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;25+&lt;/strong&gt; Pre-built essential SaaS features: Admin dashboard, App portal, Stripe Subscriptions and Payments, Blog, Page Builder, Knowledge Base, Workflows, Analytics, Internationalization, Entity Builder, Email Marketing, Notifications, Onboarding, Feature Flags, Cache and Metrics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unique features: Page builder, Workflows, Onboarding, Feature flags, Cache and metrics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An all in one SaaS Starter kit&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;30+&lt;/strong&gt; Ready to use components &amp;amp; page blocks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://saasrock.com/?via=syakir" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Get it here 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Saasykit By &lt;a href="https://x.com/AmasCreates" rel="noopener noreferrer"&gt;Ahmad Mas&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsaasykit.BD395lCj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsaasykit.BD395lCj.webp" alt="Saasykit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💲 &lt;strong&gt;Price:&lt;/strong&gt; $199 , ⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.83/5 (Editor rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Available in 2 repos: Saasykit and Saasykit tenancy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SaaSykit setup: Landing Pages, Payments, Blog, SEO, Auth, Dashboard, Analytics, Product Roadmap, Emails, Database, Multitenancy, Invoice generators, Transaction report, and UI components for your SaaS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unique features: Multitenancy, Invoice generator, Comprehensive product pricing (subscripion, one-time payment, discount system), and transaction report&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developer friendly with Coding best practices&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Discord support and lifetime updates&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://saasykit.com?aff=GLLjO" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Get it here 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Shipped By &lt;a href="https://x.com/ikoichi" rel="noopener noreferrer"&gt;Luca Restagno&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fshipped.BD4BPYfE.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fshipped.BD4BPYfE.webp" alt="Shipped"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💲 &lt;strong&gt;Price:&lt;/strong&gt; $157 , ⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.8/5 (Editor rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Shipped setup: Landing Pages, Blog, SEO, Auth, Dashboard, Payments, Emails, Database with Prisma ORM, Analytics, Waiting list, pre-sale page, affiliate program page, Chrome extension, Customer support chat, and UI Components for your SaaS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unique features: Waiting list &amp;amp; Presale page, Affiliate program page, Chrome extension&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; UI Libraries for UI components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Discord community and lifetime updates&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://shipped.club/?aff=GLLjO" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Get it here 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Larafast By &lt;a href="https://x.com/karakhanyanS" rel="noopener noreferrer"&gt;Serg&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Flarafast.cDKQROwZ.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Flarafast.cDKQROwZ.webp" alt="Larafast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💲 &lt;strong&gt;Price:&lt;/strong&gt; $199 , ⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.75/5 (Editor rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Available in TALL (Tailwind, Alpine.js, Laravel, Livewire) and VILT (Vue, Inertia, Laravel, Tailwind)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Larafast setup: Landing Page, Blog, SEO, Auth, Dashboard, Payments, Emails, Database, Waiting list page, and Open AI Adapter for your SaaS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unique features: Open AI Integration&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;30+&lt;/strong&gt; DaisyUI Theme&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://larafast.com/?aff=GLLjO" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Get it here 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  6. ShipFast By [Marc Lou][&lt;a href="https://x.com/marc_louvion" rel="noopener noreferrer"&gt;https://x.com/marc_louvion&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fshipfast.D-Lm4nGl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fshipfast.D-Lm4nGl.webp" alt="ShipFast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💲 &lt;strong&gt;Price:&lt;/strong&gt; $169 , ⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.7/5 (Editor rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An exclusive community of 4.5k+ makers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;19+&lt;/strong&gt; Ready to use components / blocks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ShipFast setup: SEO, Database, Emails, Payments, Auth, Customer Support, Error handling, and Analytics for your SaaS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Available in Typescript &amp;amp; Javascript version&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Available in App &amp;amp; Page router&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://shipfa.st/?via=syakir" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Get it here 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  7. SaaSBold By &lt;a href="https://x.com/MusharofChy" rel="noopener noreferrer"&gt;Musharof&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsaasbold.CcAR14AL.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsaasbold.CcAR14AL.webp" alt="SaaSBold"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💲 &lt;strong&gt;Price:&lt;/strong&gt; $149 , ⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.7/5 (Editor rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;SaaSBold setup: Landing Pages, Blog, SEO, Auth, Dashboard, Analytics, Payments, Emails, Database, Internalization, AI Integration, and UI components for your SaaS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unique features: AI Integration, User Dashboard, Design &amp;amp; style guide in Figma&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Discord support and lifetime updates&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://saasbold.com?aff=GLLjO" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Get it here 🚀&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>javascript</category>
      <category>startup</category>
    </item>
    <item>
      <title>How do you manage tasks when you have a lot of todos?</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Sat, 28 Sep 2024 05:26:25 +0000</pubDate>
      <link>https://dev.to/syakirurahman/how-do-you-manage-tasks-when-you-have-a-lot-of-todos-1g6p</link>
      <guid>https://dev.to/syakirurahman/how-do-you-manage-tasks-when-you-have-a-lot-of-todos-1g6p</guid>
      <description>&lt;p&gt;Hi guys,&lt;/p&gt;

&lt;p&gt;I'm struggling how to manage my tasks since a couple weeks ago. Its one of a reason i dont post new article recently.&lt;/p&gt;

&lt;p&gt;Please share your experiences or opinions how do you manage your tasks when you have a lot of todos?&lt;/p&gt;

&lt;p&gt;Thank you.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Build or Not Build?</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Fri, 20 Sep 2024 04:40:26 +0000</pubDate>
      <link>https://dev.to/syakirurahman/build-or-not-build-1jaf</link>
      <guid>https://dev.to/syakirurahman/build-or-not-build-1jaf</guid>
      <description>&lt;p&gt;Hi guys,&lt;/p&gt;

&lt;p&gt;So, yesterday, i did a keyword research for my next content for my blog, and i found a low competition keyword with high search volumes + a lot of sub keywords with relatively high search volumes as well.&lt;/p&gt;

&lt;p&gt;Then, instead of making content from it, i'm thinking to build an entire website for this keyword. It's possible to build it as a full static website.&lt;/p&gt;

&lt;p&gt;So, i research further.&lt;/p&gt;

&lt;p&gt;I found out that there are already some websites with exact contents and very similar features that i want to build. 1 of these websites has really nice UX and went viral. But its still young website (less than a year old).&lt;/p&gt;

&lt;p&gt;So, my question is, should i build this website?&lt;br&gt;
I feel demotivated when seeing all these existing websites.&lt;/p&gt;

&lt;p&gt;I really appreciate any suggestion / comment.&lt;/p&gt;

&lt;p&gt;Thanks&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>discuss</category>
      <category>help</category>
    </item>
    <item>
      <title>17 Best Free React Admin Template 2024 to Speed up Your Web App Development 🚀</title>
      <dc:creator>Syakir</dc:creator>
      <pubDate>Thu, 12 Sep 2024 12:44:31 +0000</pubDate>
      <link>https://dev.to/syakirurahman/17-best-free-react-admin-template-2024-to-speed-up-your-web-app-development-3ec</link>
      <guid>https://dev.to/syakirurahman/17-best-free-react-admin-template-2024-to-speed-up-your-web-app-development-3ec</guid>
      <description>&lt;p&gt;&lt;strong&gt;Checkout the &lt;a href="https://devaradise.com/free-react-admin-templates/" rel="noopener noreferrer"&gt;original page&lt;/a&gt; for template sorting and filtering feature ✨&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi there 👋. I'm Syakir, a Front-end engineer.&lt;/p&gt;

&lt;p&gt;Last week, i shared a post of &lt;a href="https://devaradise.com/best-react-admin-templates" rel="noopener noreferrer"&gt;curated premium react admin templates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today, i want to share the free version of it.&lt;/p&gt;

&lt;p&gt;I browsed and researched these templates, then summarize what they offer, what stacks do they use, and rate them so you can quickly decide your choice.&lt;/p&gt;

&lt;p&gt;All of them are using React 18+, and are latest updated this year. So rest assured, i don't list an outdated template.&lt;/p&gt;

&lt;p&gt;Some templates also provide the pro version, which i linked with my affiliate links. I may earn a small commission at no extra cost to you if you decide to buy the template from this link. This supports my work in providing curated resources like this one.&lt;/p&gt;

&lt;p&gt;I hope you find what you're looking for, and speed up your app development process with any template you choose here.&lt;/p&gt;

&lt;p&gt;Cheers 🥂.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Refine By Refine Dev
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Frefine.XOpiHxA0.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Frefine.XOpiHxA0.webp" alt="Refine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.8/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A React Meta-framework to build Admin panel / internal app&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt; Dashboards (CRM, Ecommerce, HR App, DepOps)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;15+&lt;/strong&gt; Backend Services Integrations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt; UI Framework supports&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extensive features&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://example.crm.refine.dev/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/refinedev/refine" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Sakai By Primefaces
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsakai.BPjrXJaR.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fsakai.BPjrXJaR.webp" alt="Sakai"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.6/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;9&lt;/strong&gt; Page templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customized PrimeReact components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Figma design files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Free Prime Blocks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://sakai.primereact.org/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/primefaces/sakai-react" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  3. CoreUI Free Admin By Core UI
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fcore-ui-free.DjIn3qX-.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fcore-ui-free.DjIn3qX-.webp" alt="CoreUI Free Admin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.57/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; Page templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Built-in CoreUI components and widgets&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Available in other frameworks: Angular, Vue, Next.js, &amp;amp; HTML (Bootstrap)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://coreui.io/demos/react/5.0/free/?theme=light" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/coreui/coreui-free-react-admin-template" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Notus React By Creative Tim
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fnotus-react.Dm9083L5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fnotus-react.Dm9083L5.webp" alt="Notus React"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.55/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;8&lt;/strong&gt; Page templates (4 Dashboard pages, 2 Auths, Landing &amp;amp; Profile page)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;18&lt;/strong&gt; Dynamic components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Available in other frameworks: Angular, Vue, Next.js, Svelte, &amp;amp; HTML&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://demos.creative-tim.com/notus-react/#/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/creativetimofficial/notus-react" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Minimal UI Free By Minimal
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fminimals.DCuvn59z.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fminimals.DCuvn59z.webp" alt="Minimal UI Free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.53/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt; Page templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Theme customizer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Elegant design&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://free.minimals.cc/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/minimal-ui-kit/material-kit-react" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Horizon UI Free By Horizon UI
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fhorizon-free.DCvaDS5z.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fhorizon-free.DCvaDS5z.webp" alt="Horizon UI Free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.5/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; Page templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Light / Dark mode supports&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Available in 2 UI framework: Chakra UI &amp;amp; Tailwind CSS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://horizon-ui.com/horizon-ui-chakra" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/horizon-ui/horizon-ui-chakra" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
 &lt;a href="https://horizon-ui.com/pro/?ref=devaradise" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Pro version 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Datta Able Free By CodedThemes
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fdatta-able-free.Cb-SFwqF.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fdatta-able-free.Cb-SFwqF.webp" alt="Datta Able Free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.5/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; Page templates (Dashboard, Login, Register)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;10+&lt;/strong&gt; UI Components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Styled form input components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://codedthemes.com/demos/admin-templates/datta-able/react/free/app/dashboard/default" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/codedthemes/datta-able-free-react-admin-template" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
 &lt;a href="https://codedthemes.com/item/datta-able-react-admin-template/?ref=syakirurahman" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Pro version 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Material Kit React By Devias
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fdevias-material-kit-react.-3vocuyG.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fdevias-material-kit-react.-3vocuyG.webp" alt="Material Kit React"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.5/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;8&lt;/strong&gt; Page templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Figma design files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://material-kit-react.devias.io/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/devias-io/material-kit-react" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Material Dashboard 2 By Creative Tim
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmaterial-dashboard.DUilEgwQ.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmaterial-dashboard.DUilEgwQ.webp" alt="Material Dashboard 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.5/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;7&lt;/strong&gt; Page templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Theme customizer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RTL support&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://demos.creative-tim.com/material-dashboard-react/#/dashboard" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/creativetimofficial/material-dashboard-react" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Argon Dashboard React By Creative Tim
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fargon-dashboard-react.HiQW3eeb.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fargon-dashboard-react.HiQW3eeb.webp" alt="Argon Dashboard React"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.5/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; Page templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Available in other frameworks: Angular, Laravel, Node.js, &amp;amp; HTML (Bootstrap)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://demos.creative-tim.com/argon-dashboard-react/#/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/creativetimofficial/argon-dashboard-react" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  11. Materio Free By ThemeSelection
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmaterio-free.CZ1GvYHG.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmaterio-free.CZ1GvYHG.webp" alt="Materio Free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.5/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;7+&lt;/strong&gt; Page Templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Light / Dark Mode&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://demos.themeselection.com/materio-mui-nextjs-admin-template-free/demo" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/themeselection/materio-mui-nextjs-admin-template-free" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  12. Mantis Free By CodedThemes
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmantis-free.BPUIfyAB.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmantis-free.BPUIfyAB.webp" alt="Mantis Free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.4/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; Page templates (Dashboard, Login, Register)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;7&lt;/strong&gt; Demo pages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://mantisdashboard.io/free/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/codedthemes/mantis-free-react-admin-template" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  13. Berry Free By CodedThemes
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fberry-free.CDTrSyYo.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fberry-free.CDTrSyYo.webp" alt="Berry Free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.4/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; Page templates (Dashboard, Login, Register)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;7&lt;/strong&gt; Demo pages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Available in Remix version&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://berrydashboard.io/free/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/codedthemes/berry-free-react-admin-template" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  14. Material Tailwind Dashboard By Creative Tim
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmaterial-tailwind-dashboard.DZwjXLAM.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmaterial-tailwind-dashboard.DZwjXLAM.webp" alt="Material Tailwind Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.4/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt; Page templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Theme customizer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://demos.creative-tim.com/material-tailwind-dashboard-react/#/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/creativetimofficial/material-tailwind-dashboard-react" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  15. MatX React Free By UI Lib
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmatx.B_FSiftb.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmatx.B_FSiftb.webp" alt="MatX React Free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.4/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; Page templates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;30+&lt;/strong&gt; UI Components based on Material UI components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://ui-lib.com/downloads/matx-free-react-admin-template/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/uilibrary/matx-react" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  16. Materially Free By CodedThemes
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmaterially-free.uEksVTSW.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmaterially-free.uEksVTSW.webp" alt="Materially Free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.3/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; Page templates (Dashboard, Login, Register)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; Demo pages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://codedthemes.com/demos/admin-templates/materially/react/free/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/codedthemes/materially-free-react-admin-template" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
 &lt;a href="https://codedthemes.com/item/materially-reactjs-admin-dashboard/?ref=syakirurahman" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Pro version 🚀&lt;/a&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  17. Mosaic Lite By Cruip
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmosaic-free.B_WOMz6P.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevaradise.com%2F_astro%2Fmosaic-free.B_WOMz6P.webp" alt="Mosaic Lite"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;Rating:&lt;/strong&gt; 4.2/5 (Personal rating)&lt;/p&gt;

&lt;p&gt;🍔 &lt;strong&gt;Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Professional and Elegant Design&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lite version only offer 1 Dashboard page&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Light / Dark Mode&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Well documented&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Community support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://mosaic.cruip.com/" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Live demo 🚀&lt;/a&gt;
 &lt;a href="https://github.com/cruip/tailwind-dashboard-template" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Details 📑&lt;/a&gt;
&lt;/p&gt;

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