Zostel
Site Newsletter Signup

Newsletter Signup

The newsletter at the foot of a page: a title, a line, an email field with its label and Subscribe. It checks before it sends and says what happened.

Preview

Stories from the road, in your inbox

New places, new trips and what's on at the Zostels. Once a month, no noise.

Usage

tsx
import { NewsletterSignup } from "zostel-ui";

<NewsletterSignup
  action="/api/newsletter"
  onSubscribe={async (email) => {
    await fetch("/api/newsletter", { method: "POST", body: JSON.stringify({ email }) });
  }}
/>

Props

onSubscribe
Type: (email: string) => void | Promise<void>
Default: —

Required: called with a valid address (without it nothing is sent, so it could never honestly say you’re in). A promise shows “Sending…”, with the field read-only and Subscribe aria-disabled, so the focus stays; a rejection says it didn’t go through and puts the focus back in the field.

action · method
Type: string · string
Default: — · "post"

Where the form posts before the script runs, or without it. method is post, so the address goes in the request’s body, never into the page’s URL.

titleAs
Type: "h2" | "h3" | "h4" | "p"
Default: "h3"

The title’s element, so it sits in the page’s outline.

title · body
Type: ReactNode
Default: —

The heading and the line beside the field.

buttonLabel
Type: string
Default: "Subscribe"

The button’s word.

doneMessage
Type: ReactNode
Default: "You're in. Watch your inbox."

What it says once you’re in.

className
Type: string
Default: —

More classes, merged with the component’s own (tailwind-merge).

On zostel.com

Above the footer of every page. The field has a real label, a wrong address is said in words next to it (not only in red), and the status lives in a polite live region.