Add subscribe to newsletter to your Remix app in 2 ways

16th September 2022 | 5 min read
webdevelopmentreacttypescriptvercelremixssrformssubscribeexampleopen source
showing github commits

This is how you can add subscribe to newsletter feature in your Remix app. You can do it in 2 ways, explained below.

Note: This will not cover the actual subscribe implmenetation, you can use any service you want, like Mailchimp, Sendgrid, etc. The server side code is not integrated so you can easily add your favourite service.

We will use TailwindCSS for styling, but you can use any CSS framework you want.

1. Using Form and Redirect

The first way is to use a form and redirect the user to a thank you page. This is the most common way to do it, but it has a drawback - the user will not be able to go back to the page he was previously on. This is not a big deal if you have a small website, but if you have a lot of pages, it can become a problem.

We will use Remix's Form Component

<Form
		method="post"
		action="/newsletter/subscribe-with-redirect"
		id="subscribe-form-footer"
		className="flex justify-center items-center md:w-96 sm:w-72 pt-5 w-full">
		<input
			type="email"
			name="email"
			id="email"
			placeholder="Your email"
			className="w-full h-10 px-3 text-base bg-primary-complement placeholder-white border rounded-lg focus:shadow-outline border-secondary-complement border-r-0 rounded-r-none"
			required
		/>
		<button
			type="submit"
			value="subscribe"
			className="bg-primary-complement rounded-lg border-l-0 rounded-l-none h-10 border-secondary-complement border px-1">
			<svg
				className="w-6 h-6 text-white"
				fill="none"
				stroke="currentColor"
				viewBox="0 0 24 24"
				xmlns="http://www.w3.org/2000/svg">
				<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
			</svg>
		</button>
	</Form>

Server handler code:

import { redirect } from '@remix-run/node';

import type { ActionFunction } from '@remix-run/node';

export const action: ActionFunction = async ({ request }) => {
	try {
		const email = (await request.formData()).get('email');

		// throw new Error('test error');
		return redirect('/newsletter/thanks', { headers: { 'Set-Cookie': `subscribedEmail=${email}` } });
	} catch (error) {
		return redirect('/newsletter/error', { headers: { 'Set-Cookie': 'error=true' } });
	}
};

From here we need to define 2 new routes:

Takeaways

Remix's Form component will handle the form submission and the server side will handle the service call, redirection.

This works just like a normal form in a regular HTML page.

This will work even if your JavaScript is disabled.

2. Using useFetcher to show a success message

But maybe you don't want to redirect the user, maybe you want to show a success message on the same page. This is where the useFetcher hook comes in handy.

We will use Remix's useFetcher hook

Most of the code could be also found in Remix Documentation, what this example has extra is that we are showing a success message after the user subscribes.

The success message is display within a modal created with TailwindCSS.

We are also handling the error case and showing a message to the user.

All the code is open source you can find a link to the repo at the end of the article.

import { useEffect, useRef, useState } from 'react';
import { useFetcher } from '@remix-run/react';

import type { FC, ReactElement } from 'react';

import Modal from '~/components/Modal';

const SubscribeToNewsletter: FC = (): ReactElement => {
	const newsletter = useFetcher();
	const [isModalOpen, setIsModalOpen] = useState(false);

	const formRef = useRef<HTMLFormElement>(null);

	const toggleModal = (toggler: boolean) => {
		setIsModalOpen(toggler);
	};

	useEffect(() => {
		if (newsletter.type === 'done' && newsletter.data.success) {
			formRef.current?.reset();
			toggleModal(true);
		}
	}, [newsletter]);

	return (
		<>
			<newsletter.Form
				method="post"
				ref={formRef}
				action="/newsletter/subscribe"
				id="subscribe-form-footer"
				className="flex justify-center items-center md:w-96 sm:w-72 pt-5 w-full">
				<input
					type="email"
					name="email"
					id="email"
					placeholder="Your email"
					className="w-full h-10 px-3 text-base bg-primary-complement placeholder-white border rounded-lg focus:shadow-outline border-secondary-complement border-r-0 rounded-r-none"
					required
				/>
				<button
					type="submit"
					value="subscribe"
					disabled={newsletter.state === 'submitting'}
					className={`bg-primary-complement rounded-lg border-l-0 rounded-l-none h-10 border-secondary-complement border px-1 ${
						newsletter.state === 'submitting' ? 'opacity-70' : 'opacity-100'
					}`}>
					<svg
						className="w-6 h-6 text-white"
						fill="none"
						stroke="currentColor"
						viewBox="0 0 24 24"
						xmlns="http://www.w3.org/2000/svg">
						<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
					</svg>
				</button>
				{newsletter.type === 'done' && newsletter.data.error && (
					<span className="absolute text-red-700 mt-20">Something went wrong ...</span>
				)}
			</newsletter.Form>
			<Modal
				isOpen={isModalOpen}
				onClose={() => {
					toggleModal(false);
				}}
				title={'Subscribed!'}
				subtitle={`Thank you ${
					newsletter.type === 'done' && newsletter.data.subscribedEmail
				}. You are now subscribed to our newsletter.`}
			/>
		</>
	);
};

export default SubscribeToNewsletter;

Server handler code:

import { json } from '@remix-run/node';

import type { ActionFunction } from '@remix-run/node';

export const action: ActionFunction = async ({ request }) => {
	try {
		const email = (await request.formData()).get('email');

		// throw new Error('test error');
		return {
			success: true,
			subscribedEmail: email,
		};
	} catch (error) {
		return json({ error: true });
	}
};

Note how here we are using the json function from Remix to return a JSON response. This is because we are not redirecting the user, we are just returning a JSON response. This comes handy when we want to return different data from a server side action.

The 2nd case won't work if you have JavaScript disabled, but the first one will.

See it in action

I created a playground (https://playground.robipop.dev) where you can see the examples in action.

The playground is open source you can see it here:

https://github.com/robipop22/playground

Conclusion

Remix is a great tool for building modern web applications. It's easy to use and it's very flexible. A benefit is that all of these are built on top of Web Standards.

I hope you enjoyed this article and learned something new. If you have any questions or suggestions please reach out to me via twitter/email.

Keep on coding! 🚀

Read More Posts