2 minute read

How to Add Newsletter Signup (Revue) to a Static Site (Gatsby)

This post covers how to add newsletter functionality to a static website. In this case I used the Revue newsletter service and added it using a form to this website which is built using Gatsby.

revue
Newsletter homepage on Revue for victordibia.com.

Newsletter Design Goals

A newsletter can be a great way to share content with readers and build an audience. Starting out, I wanted a good user experience flow:

  • Provide a signup form (a react component) can can be embedded in pages, blog posts .. essentially anywhere on a Gatsby website.
  • Allow the entire signup process to happen within the component (Async). No page refresh or redirection. This would involve making a call to the newsletter api to add the user's email address and showing an update for successful or fail attempts.

The main challenge with the above is that making api calls from a static website (e.g. using javascript Fetch) to a different newsletter api server introduces security issues and is generally not supported (see CORS2 errors discussion ). An alternative would be to write a backend api that makes this call and forwards the result to the frontend hosted on same server. However, I host my website on Github pages, so the possibility of writing a backend api just did not work.

Here is the workflow I settled on with Revue:

  • Insert Revue form in component.
  • Validate email on form submit.
  • Submit form to revue "Add subscriber" page (this is done after a slight delay to give the illusion of some local processing being done). This is a redirect which I have to accomodate.

Why Revue?

There are multiple mail services (with comparable basic functionality) that you can use for a newsletter e.g. MailChimp, Substack and Revue 1 3. MailChimp 4 has an excellent gatsby plugin which I tried out for the first version of my newsletter explorations. Some reasons I have decided to try Revue as at time of writing:

  • They have been recently acquired by Twitter, it is likely the product will improve. Or not. 🤷
  • They provide unlimited subscribers compared to MailChimp capped at 2k subscribers.
  • They offer the configuration of a custom domain. For example I was able to map join.victordibia.com to my Revue profile page. This helps with maintaining the illusion of a single victordibia.com experience.

Writing Some Code

Add a form

Add html form to component. Revue provides sample form integration code (go to your account settings -> integrations -> sign up forms). The form can contain additional details such as first name and last name etc. We will edit the default to just capture email address as shown below.

<div id={formID} className=" inline-block">
<div id="revue-embed">
  <form
    action="http://join.victordibia.com/add_subscriber"
    method="post"
    id="revue-form"
    name="revue-form"
    target="_blank">
    <div className="revue-form-group">
      <input
        placeholder="email@example.com"
        type="email"
        name="member[email]"
        id="member_email"
      ></input>
    </div>

    <div className="revue-form-actions">
      <button
        type="submit"
        onClick={subscribeClick}
        name="member[subscribe]"
        id="member_submit">
         Subscribe
      </button>
    </div>
  </form>
</div>

Add Some Javascript

Note that the submit button above has an onClick event which :

  • prevents default submit behaviour
  • validates the email address. This shows or hides an error message as needed
  • submits the form if email validation checks out .. this triggers a redirect to the Revue profile page. The delays (setTimeout) are used to display a loading spinner for a short duration before the redirect. This communicates activity to the user and prepares them for the coming redirect.

Snippets for onClick are shown below.

function subscribeClick(e) {
  e.preventDefault();
  const email = currentForm.querySelector("#member_email").value;
  const isEmailValid = validateEmail(email);

  const emailError = currentForm.querySelector("#email_error");
  const subSuccess = currentForm.querySelector("#subscribe_success");
  const subLoading = currentForm.querySelector("#subscribe_loading");
  const revueForm = currentForm.querySelector("#revue-form");

  if (isEmailValid) {
    subLoading.classList.remove("hidden");
    emailError.classList.add("hidden");
    setTimeout(() => {
      subLoading.classList.add("hidden");
      subSuccess.classList.remove("hidden");
      revueForm.submit();
    }, loadDuration);
  } else {
    subLoading.classList.remove("hidden");
    setTimeout(() => {
      resetViews();
      emailError.classList.remove("hidden");
    }, loadDuration);
  }
}

And really, thats it!

References

Interested in more articles like this? Subscribe to get a monthly roundup of new posts and other interesting ideas at the intersection of Applied AI and HCI.
Powered by Revue. Privacy Policy.

RELATED POSTS | web

Join the Newsletter.

Powered by Revue. Privacy Policy.

Subscribe to get a monthly newsletter on Applied AI and HCI .

Feel free to reach out! Twitter, GitHub, LinkedIn

.