<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Cindy Potvin</title>
    <description>The latest articles on Forem by Cindy Potvin (@cindyptn).</description>
    <link>https://forem.com/cindyptn</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%2F703042%2F248a9ccc-2563-4e52-89bc-08e4953bbda5.png</url>
      <title>Forem: Cindy Potvin</title>
      <link>https://forem.com/cindyptn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/cindyptn"/>
    <language>en</language>
    <item>
      <title>Coming up with with my new Micro SaaS technological stack</title>
      <dc:creator>Cindy Potvin</dc:creator>
      <pubDate>Tue, 17 Jan 2023 16:50:47 +0000</pubDate>
      <link>https://forem.com/cindyptn/coming-up-with-with-my-new-micro-saas-technological-stack-3i2b</link>
      <guid>https://forem.com/cindyptn/coming-up-with-with-my-new-micro-saas-technological-stack-3i2b</guid>
      <description>&lt;p&gt;For my next project, I’ve been assembling a new technological stack to create micro SaaS apps quickly and cheaply before jumping in the code. I’ve not put it to the test yet, but I figured it would be interesting to share how I’ve reasoned about it.&lt;/p&gt;

&lt;p&gt;I’m now working with small clients, but I was previously working on bigger enterprise projects where the concerns were different, and I’m missing a few tools in my (virtual) tool bag for the smaller, more nimble stuff. I also have ideas that I want to bring to life and I’m looking to build a set of technologies I can reuse across projects and get to the main features quicker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cindypotvin.com/wp-content/uploads/2023/01/pexels-anete-lusina-4792489-scaled.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I-H0CPV0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cindypotvin.com/wp-content/uploads/2023/01/pexels-anete-lusina-4792489-1024x684.jpg" alt="" width="880" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Main goals
&lt;/h2&gt;

&lt;p&gt;I don’t mind paying for services that save me time or give me a significant advantage, but the main goal is to deploy each additional applications for cheap since they won’t be using a lot of resources, at least at first.&lt;/p&gt;

&lt;p&gt;If I can keep the bar to profitability lower, I can launch more experiments and each micro SaaS will need a lower MRR (monthly recurring revenue) to earn their keep. It’s hard to know application will be a hit, so I want to be able to keep building without adding 50$-100$ a month to my spending for each application.&lt;/p&gt;

&lt;p&gt;Still, I also need to keep my maintenance time low, both since I don’t have a lot of time for my own projects and because I hand off projects to clients and want to keep them as easy to maintain as I can.&lt;/p&gt;

&lt;p&gt;If I can use only a few tools with a minimum of custom work between them, it would be best. I’m trying to save money, but it will be more expensive in the long run if I’m stuck maintaining 20 Ubuntu installs holding random Docker images, and remembering all the glue scripts I came up with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;

&lt;p&gt;I got started on my frontend stack with &lt;a href="https://divjoy.com/"&gt;Divjoy&lt;/a&gt; as a SaaS template to handle the common boilerplate. It includes many of the tools I was looking to use such as Material UI in the frontend and Stripe for payment.&lt;/p&gt;

&lt;p&gt;There are a few other good UI kits that comes with the Divjoy, but I’m already familiar with Material UI: it looks nice and it’s easy to theme.&lt;/p&gt;

&lt;p&gt;I also need some JavaScript error monitoring since I won’t always keep a close eye on the application. It’s a toss-up between &lt;a href="https://sentry.io"&gt;Sentry&lt;/a&gt; and &lt;a href="https://rollbar.com"&gt;Rollbar&lt;/a&gt;. Their free tier is similar, but I liked the Sentry error management with the little experience I had of it, so let’s go with Sentry for now.&lt;/p&gt;

&lt;p&gt;For hosting the frontend static files, I’ll go with &lt;a href="https://vercel.com"&gt;Vercel&lt;/a&gt; since they have unlimited sites. I may also try their Next.js framework at some point with server-side rendering and it just works. Netlify would have been a good option at a similar price point, but their marketing material was not as clear about how many sites were allowed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend
&lt;/h2&gt;

&lt;p&gt;Since my projects are simple, I want to aim for a “backend as a service” first and see what else I need if I hit any limits. This should handle all the main backend parts like the database and its api, authentication and file storage.&lt;/p&gt;

&lt;p&gt;I’m afraid of pay-as-you-go like &lt;a href="http://firebase.google.com"&gt;Firebase&lt;/a&gt; since I’m not going to keep a close eye on everything across many applications and don’t want Google to send me a big bill if I make a mistake. I prefer something with a clear cap.&lt;/p&gt;

&lt;p&gt;For this reason, I’m going to settle on &lt;a href="https://supabase.com/"&gt;Supabase&lt;/a&gt; for my backend as a service. Given that I don’t want to too much maintenance, I’ll purchase from Supabase instead of self hosting it.&lt;/p&gt;

&lt;p&gt;Only problem with Supabase is that they’re charging that 25$ per project, but if I structure my data well I should be able to reuse that for all my projects. I can always spin off another project and move the data if I want to sell one of the micro SaaS, or if one really takes off and uses up too much of the quota.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other infrastructure
&lt;/h2&gt;

&lt;p&gt;I use &lt;a href="https://www.namecheap.com/"&gt;Namecheap&lt;/a&gt; as my registrar already with &lt;a href="https://www.cloudflare.com"&gt;Cloudflare&lt;/a&gt; as the DNS server for a few small sites like this blog so I can configure emails and the like separately, so I’ll keep going with that solution. Right now the free plan does the job since I’m only using them for the DNS and some tiny static sites on Cloudflare Workers.&lt;/p&gt;

&lt;p&gt;For git source control I already have a bunch of private projects on &lt;a href="https://bitbucket.org"&gt;Bitbucket&lt;/a&gt; and I have no problems with it, so I’ll stick with it.&lt;/p&gt;

&lt;p&gt;Finally, I’ll be adding &lt;a href="https://uptimerobot.com"&gt;UptimeRobot&lt;/a&gt; to minimally keep an eye on things and check if each project is still up. The free plan should be enough for my needs for a while since it can monitor the uptime of 50 “things” such as a SSL certificate or a specific page. I’m probably just going to monitor a single page that requires api calls for each project since most elements are provided by third-party services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting budget
&lt;/h2&gt;

&lt;p&gt;Here is how it should cost to keep all my micro SaaS up, at least while they are small:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Products&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pricing (in USD)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vercel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;20$ for the cheapest commercial tier with 1TB bandwidth and preview deploys.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sentry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0$ for 5k errors logged. I doubt I’ll reach the 26$ plan with 50k error anytime soon.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supabase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;25$ for the paid tier so the database stays up.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloudflare&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0$ for the free tier with unlimited DNS server.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Postmark&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10$ for the first 10 000 emails a month, transactional or newsletter.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bitbucket&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0$ for the free tier with unlimited private repo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UptimeRobot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0$ for 50 free items monitored.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Domain name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;About 1$-ish by domain depending on the TLD.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So I’m looking at around 55$ +1$ each for the domain to run a bunch of tiny SaaS applications, not bad!&lt;/p&gt;

&lt;p&gt;If I do make a sale I’ll have Stripe fees at the minimum, and I’ll need to do support and marketing but that will need to be considered in each product’s pricing.&lt;/p&gt;

&lt;p&gt;My next step is now to try this out with my next micro SaaS to see if I missed anything and how it will turn out.&lt;/p&gt;

</description>
      <category>entrepreneurship</category>
      <category>programming</category>
      <category>sideprojects</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Hosting a static website for free in 15 minutes with Cloudflare Workers Sites</title>
      <dc:creator>Cindy Potvin</dc:creator>
      <pubDate>Thu, 20 Oct 2022 21:00:41 +0000</pubDate>
      <link>https://forem.com/cindyptn/hosting-a-static-website-for-free-in-15-minutes-with-cloudflare-workers-sites-27mp</link>
      <guid>https://forem.com/cindyptn/hosting-a-static-website-for-free-in-15-minutes-with-cloudflare-workers-sites-27mp</guid>
      <description>&lt;p&gt;I’ve had an old school PHP hosting for ages, and I’m currently moving all the sites I’m hosting there to newer and more effective technologies.&lt;/p&gt;

&lt;p&gt;I have a few static sites included in the mix: I’ve been writing pure HTML + CSS for so long that it’s still my favorite solution if I want to spin up a quick landing page for a project.&lt;/p&gt;

&lt;p&gt;The best solution for me ended up being Cloudflare’s Worker Sites. The setup is simpler than using a static page generator, and once it’s done a new version can be deployed in an instant with a single command. The server is quick, and it’s free (up to a decent bit of traffic)!&lt;/p&gt;

&lt;p&gt;Cloudflare also has a Pages product that takes the static result of a build from a git repository from a site built with tools such as React, but I have not tested it, and my use case is simple enough right now that it’s not worth setting up a git repo for each site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Site to deploy
&lt;/h2&gt;

&lt;p&gt;I decided to start the move with one of my newest project: &lt;a href="http://manibas.com"&gt;http://manibas.com&lt;/a&gt;, a site to sell my hand cranked socks. For a quick rundown of the landing page :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML/CSS all the way, except one little bit of JavaScript to display the site in English or French depending on the language of the browser, and for a button to switch manually. &lt;/li&gt;
&lt;li&gt;Pure CSS without a framework or library. I used &lt;a href="https://coolors.co"&gt;https://coolors.co&lt;/a&gt; to help me pick colors and &lt;a href="https://fontjoy.com/"&gt;https://fontjoy.com/&lt;/a&gt; to pick fonts.&lt;/li&gt;
&lt;li&gt;Payment is handled by a Stripe Payment button. I have a US/Canada and an International button since the shipping price is too different. I’ll handle the rest, such as sizing and color by email when I have orders.&lt;/li&gt;
&lt;li&gt;No contact form, people can reach out on Instagram if they have more questions or comments.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;You’ll need the LTS version of NodeJS to install the required tool, a free Cloudflare account and a domain name to point to the site that’s already going through Cloudflare.&lt;/p&gt;

&lt;p&gt;You also need an &lt;code&gt;index.html&lt;/code&gt; file ready to deploy (ideally with a few other assets like images).&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the project
&lt;/h2&gt;

&lt;p&gt;To deploy the site, you need to install Wrangler, the command line tool to work with Cloudflare Workers. In any folder, run &lt;code&gt;npm install&lt;/code&gt; to install the tool globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g wrangler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After having installed Wrangler, initialize the project from the folder you want to use, which will create a &lt;code&gt;package.json&lt;/code&gt; and the required boilerplate:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;There is a small bit missing, since you’ll most likely have more than just a &lt;code&gt;index.html&lt;/code&gt; file and will need to route to other static assets such as images, fonts or an external CSS file. Install the package that handles routing to static assets inside Cloudflare Workers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev @cloudflare/kv-asset-handler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, replace the content of the generated &lt;code&gt;src/index.ts&lt;/code&gt; with the following code snippet from the Cloudflare documentation to handle the routing (&lt;a href="https://developers.cloudflare.com/workers/platform/sites/start-from-existing"&gt;https://developers.cloudflare.com/workers/platform/sites/start-from-existing&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { getAssetFromKV } from "@cloudflare/kv-asset-handler";

addEventListener("fetch", (event) =&amp;gt; {
  event.respondWith(handleEvent(event));
});

async function handleEvent(event) {
  try {
    // Add logic to decide whether to serve an asset or run your original Worker code
    return await getAssetFromKV(event);
  } catch (e) {
    let pathname = new URL(event.request.url).pathname;
    return new Response(`"${pathname}" not found`, {
      status: 404,
      statusText: "not found",
    });
  }
}

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

&lt;/div&gt;



&lt;p&gt;Finally, specify the root URL to use and the folder containing the files that needs to be published in the &lt;code&gt;wrangler.toml&lt;/code&gt; file that was created by Wrangler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;route = "https://manibas.com/*"[site]bucket = "./public"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploying the static page
&lt;/h2&gt;

&lt;p&gt;To deploy, move all the content that needs to be published under the &lt;code&gt;public&lt;/code&gt; folder that was specified in the &lt;code&gt;wrangler.toml&lt;/code&gt;, including an &lt;code&gt;index.html&lt;/code&gt; file as the root file.&lt;/p&gt;

&lt;p&gt;Your site is now ready to deploy! Run that last command in the folder of the project, and Wrangler will upload your static files and push it live using domain name your specified.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx wrangler publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it’s your first time running Wrangler to connect to Cloudflare, it will also ask you to authenticate to your account and to enable Workers if they are not active yet, but it will remember your identity for a while. You just need to run that command again if you want to deploy a new version of the site.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webapplication</category>
    </item>
    <item>
      <title>How to close a React Native modal with a button</title>
      <dc:creator>Cindy Potvin</dc:creator>
      <pubDate>Mon, 16 Aug 2021 10:39:00 +0000</pubDate>
      <link>https://forem.com/cindyptn/how-to-close-a-react-native-modal-with-a-button-1h79</link>
      <guid>https://forem.com/cindyptn/how-to-close-a-react-native-modal-with-a-button-1h79</guid>
      <description>&lt;p&gt;I’ve been working with React Native lately, and I’ve come across a few unimplemented features I needed to add to the basic components. One of those components is the React Native &lt;em&gt;Modal&lt;/em&gt; component that is used to show a view above another one. It doesn’t promise more features than that, but it can be very useful to implement your own popup.&lt;/p&gt;

&lt;p&gt;On the other hand, since it’s only a simple modal, it does not include everything you would expect for a popup component like an X to close it, or closing the modal when you tap beside it. I’ll be walking you through how to add those two features when you’re starting from a &lt;em&gt;Modal&lt;/em&gt; component.&lt;/p&gt;

&lt;p&gt;If you’re in a hurry, you can also find the final result on my GitHub: &lt;a href="https://github.com/CindyPotvin/react-native-popup"&gt;https://github.com/CindyPotvin/react-native-popup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.cindypotvin.com/wp-content/uploads/2021/08/Screenshot_20210813-211004.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IxoLlW7---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.cindypotvin.com/wp-content/uploads/2021/08/Screenshot_20210813-211004-576x1024.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to close a modal
&lt;/h2&gt;

&lt;p&gt;Let’s start with a basic &lt;em&gt;App.js&lt;/em&gt; that shows a popup. I also added a few styles to have a shadow so the popup is visible, and a generous amount of margin so we can test closing the popup by clicking beside it later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import React, { useState } from 'react';
import { StyleSheet, Modal, Text, View } from 'react-native';

export default function App() {
  const [modalVisible, setModalVisible] = useState(true);

  return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;Text&amp;gt;Open up App.js to start working on your app!&amp;lt;/text&amp;gt;
      &amp;lt;Modal visible={modalVisible}&amp;gt;
        &amp;lt;View style={styles.modal}&amp;gt;
          &amp;lt;Text&amp;gt;
            Popup content.
          &amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
      &amp;lt;/Modal&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "white",
    alignItems: "center",
    justifyContent: "center",
  },
  modal: {
    flex: 1,
    margin: 50,
    padding: 5,
    backgroundColor: "white",
    shadowColor: "black",
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 4,
    elevation: 5,
  },
});

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

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;Modal&lt;/em&gt; is displayed according to its &lt;em&gt;visible&lt;/em&gt; prop. Right now, the value in the state is always true, so the popup will always be visible.&lt;/p&gt;

&lt;p&gt;Even without a button or another way to change the state, the &lt;em&gt;Modal&lt;/em&gt; can be closed on Android with the back button (the menu button on Apple TV should have the same effect according to the documentation, but I don’t have one to test).&lt;/p&gt;

&lt;p&gt;Pressing the button calls the function specified in the &lt;em&gt;onRequestClose&lt;/em&gt; prop of the modal, so let’s change the state to hide the popup when it is pressed, which will show the main screen of the application :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;Modal
  visible={modalVisible}
  onRequestClose={() =&amp;gt; setModalVisible(false)}&amp;gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to add close button to a React Native modal
&lt;/h2&gt;

&lt;p&gt;First, we have to add the button itself so we can then use it to close the popup. In that case, I wanted to add a small X in the top right corner of the popup, but it could be anywhere else.&lt;/p&gt;

&lt;p&gt;Given how the positioning work, there are two options for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Positioning absolutely the button in the top right corner. You can then do anything you want for the rest of the content, but then you run the risk of having the content overlapping the X since it’s out of the normal layout flow. If you want to use the space beside and under the button at the same time, it’s pretty much impossible, which leads us to the second option.&lt;/li&gt;
&lt;li&gt;Positioning the button with flexbox, leaving space to the left of the button for a header. You can then fill in the header and the content at the bottom separately. If you’re doing something that’s meant to be a popup, having a title is also a pretty standard feature.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the component now looks like with an X added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import React, { useState } from 'react';
import { StyleSheet, Modal, Text, View, TouchableOpacity } from 'react-native';

export default function App() {
  const [modalVisible, setModalVisible] = useState(true);

  return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;Text&amp;gt;Open up App.js to start working on your app!&amp;lt;/Text&amp;gt;
      &amp;lt;Modal visible={modalVisible} 
             onRequestClose={() =&amp;gt; setModalVisible(false)}&amp;gt;
        &amp;lt;View style={styles.modal}&amp;gt;
          &amp;lt;View style={styles.modalHeader}&amp;gt;
            &amp;lt;View style={styles.modalHeaderContent}&amp;gt;
               &amp;lt;Text&amp;gt;Other header content&amp;lt;/Text&amp;gt;&amp;lt;/View&amp;gt;
               &amp;lt;TouchableOpacity&amp;gt;
                 &amp;lt;Text 
                    style={styles.modalHeaderCloseText}&amp;gt;X&amp;lt;/Text&amp;gt;   
               &amp;lt;/TouchableOpacity&amp;gt;
          &amp;lt;/View&amp;gt;
          &amp;lt;View style={styles.modalContent}&amp;gt;
            &amp;lt;Text&amp;gt;
              Popup content.
            &amp;lt;/Text&amp;gt;
          &amp;lt;/View&amp;gt;
        &amp;lt;/View&amp;gt;
      &amp;lt;/Modal&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "white",
    alignItems: "center",
    justifyContent: "center",
  },
  modal: {
    flex: 1,
    margin: 50,
    padding: 5,
    backgroundColor: "white",
    shadowColor: "black",
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 4,
    elevation: 5,
  },
  /* The content of the modal takes all the vertical space not 
     used by the header. */
  modalContent: {
    flex: 1
  },
  modalHeader: {
    flexDirection: "row",
  },
  /* The header takes up all the vertical space not used by the 
     close button. */
  modalHeaderContent: {
    flexGrow: 1,
  },
  modalHeaderCloseText: {
    textAlign: "center",
    paddingLeft: 5,
    paddingRight: 5
  }
});

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

&lt;/div&gt;



&lt;p&gt;The header is a flex container that’s displayed as a row, with &lt;code&gt;flexGrow:1&lt;/code&gt; to indicates that it should take up all the remaining space.&lt;/p&gt;

&lt;p&gt;The rest of the content in the popup is a &lt;code&gt;flex:1&lt;/code&gt; item so it takes up all the remaining height.&lt;/p&gt;

&lt;p&gt;The only thing remaining at this point is to wire up the button so it does close the popup, in the same way we set it in on the &lt;em&gt;onRequestClose&lt;/em&gt; event earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;TouchableOpacity onPress={() =&amp;gt; setModalVisible(false)}&amp;gt;
  &amp;lt;Text style={styles.modalHeaderCloseText}&amp;gt;X&amp;lt;/Text&amp;gt;
&amp;lt;/TouchableOpacity&amp;gt;       

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to close the modal by clicking outside
&lt;/h2&gt;

&lt;p&gt;To also close the modal by tapping outside, we need an additional component to catch those taps.&lt;/p&gt;

&lt;p&gt;On the other hand, we don’t want this component to catch taps meant for the child component: clicking the popup itself should not close it. By checking &lt;code&gt;event.target == event.currentTarget&lt;/code&gt;, we validate that the item selected is the component itself and not one of its children.&lt;/p&gt;

&lt;p&gt;I used a &lt;em&gt;Pressable&lt;/em&gt; component because I didn’t want the “dimming” effect on tap when touching outside the popup that comes with the &lt;em&gt;TouchableOpacity&lt;/em&gt;. This new &lt;em&gt;Pressable&lt;/em&gt; component wraps all the components we previously defined in the modal.&lt;/p&gt;

&lt;p&gt;Here is the completed popup, with a few extra borders to show where are the header and popup content :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import React, { useState } from 'react';
import { StyleSheet, Modal, Text, View, Pressable, TouchableOpacity } from 'react-native';

export default function App() {
  const [modalVisible, setModalVisible] = useState(true);
  return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;Text&amp;gt;Open up App.js to start working on your app!&amp;lt;/Text&amp;gt;
      &amp;lt;Modal
        visible={modalVisible}
        onRequestClose={() =&amp;gt; setModalVisible(false)}&amp;gt;
        &amp;lt;Pressable style={styles.outsideModal}
          onPress={(event) =&amp;gt; { 
            if (event.target == event.currentTarget) { 
               setModalVisible(false); } }} &amp;gt;
          &amp;lt;View style={styles.modal}&amp;gt;
            &amp;lt;View style={styles.modalHeader}&amp;gt;
              &amp;lt;View style={styles.modalHeaderContent}&amp;gt;
                 &amp;lt;Text&amp;gt;Other header content&amp;lt;/Text&amp;gt;
              &amp;lt;/View&amp;gt;
              &amp;lt;TouchableOpacity 
                 onPress={() =&amp;gt; setModalVisible(false)}&amp;gt;
                &amp;lt;Text style={styles.modalHeaderCloseText}&amp;gt;X&amp;lt;/Text&amp;gt;
              &amp;lt;/TouchableOpacity&amp;gt;
            &amp;lt;/View&amp;gt;
            &amp;lt;View style={styles.modalContent}&amp;gt;
              &amp;lt;Text&amp;gt;
                Popup content.
              &amp;lt;/Text&amp;gt;
            &amp;lt;/View&amp;gt;
          &amp;lt;/View&amp;gt;
        &amp;lt;/Pressable&amp;gt;
      &amp;lt;/Modal&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "white",
    alignItems: "center",
    justifyContent: "center",
  },
  modal: {
    flex: 1,
    margin: 50,
    padding: 5,
    backgroundColor: "white",
    shadowColor: "black",
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.25,
    shadowRadius: 4,
    elevation: 5,
  },
  /* The content of the modal takes all the vertical space not 
     used by the header. */
  modalContent: {
    flex: 1,
    borderWidth: 1,
    borderColor: "black"
  },
  modalHeader: {
    flexDirection: "row",
    borderWidth: 1,
    borderColor: "black"
  },
  /* The header takes up all the vertical space not used by the 
     close button. */
  modalHeaderContent: {
    flexGrow: 1,
  },
  modalHeaderCloseText: {
    textAlign: "center",
    paddingLeft: 5,
    paddingRight: 5
  },
  outsideModal: {
    backgroundColor: "rgba(1, 1, 1, 0.2)",
    flex: 1,
  }
});

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

&lt;/div&gt;



&lt;p&gt;Please note that there is a small limitation to this: the background color for a &lt;em&gt;Pressable&lt;/em&gt; or a &lt;em&gt;TouchableOpacity&lt;/em&gt; cannot be set to a transparent or a semi-transparent value, so the content under the popup will no longer be visible.&lt;/p&gt;

&lt;p&gt;A next step to make this better would be to package the &lt;em&gt;Modal&lt;/em&gt; components and all its content into a new component that can be reused in your application so you can insert any header or content in the popup, but this is outside the scope of the current article.&lt;/p&gt;

&lt;p&gt;If you want to execute the final version yourself and try it out, you can see it on GitHub here: &lt;a href="https://github.com/CindyPotvin/react-native-popup"&gt;https://github.com/CindyPotvin/react-native-popup&lt;/a&gt; and as an Expo Snack here: &lt;a href="https://snack.expo.dev/@cindyptn/react-native-popup-with-x-button"&gt;https://snack.expo.dev/@cindyptn/react-native-popup-with-x-button&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>javascript</category>
      <category>programming</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
