A passwordless magic link login screen in pure CSS and vanilla JavaScript. Users enter only their email, and the screen switches to a "Check your inbox" state with an Open mail app button and a resend countdown. It is an HTML mobile template for mobile websites and PWAs and can be packaged as a native app with Capacitor; use it as the email link sign in page of a SaaS, team or membership app.
How it works
The root .pml-app is a 430 px app column with a top bar (back button, brand, Help link) and two views: [data-pml-view="email"] and [data-pml-view="sent"]. The current view is also written to data-pml-state on the root.
The email view has an inline SVG illustration, a form with one type="email" input (autocomplete="email", inputmode="email") and two reassurance points in .pml-points. The form has novalidate: on submit the script checks for an empty or malformed address, sets aria-invalid and shows a specific message in #pml-email-error.
A valid address runs sendLink(), a simulated request that waits SEND_DELAY milliseconds while the button shows a spinner. Then show('sent') swaps the views, writes the address into [data-pml-address] and moves focus to the heading. startTimer() counts down from RESEND_SECONDS in [data-pml-time]; at zero the countdown is replaced by the Resend link button. Resending restarts the timer and shows a short .pml-toast confirmation. The back button and "use a different email" return to the form with the address selected.
The Open mail app button is a plain mailto: link; inside a Capacitor app you can replace it with a call that opens the default mail client.
Customization
--pml-primaryand--pml-primary-darkinstyle.css: button, link, icon and focus colours.--pml-tintand--pml-tint-2: the light violet backgrounds of the info box and address pill.RESEND_SECONDSinscript.js: how long users wait before they can ask for a new link.SEND_DELAYandsendLink()inscript.js: replace the timeout with yourfetch()call to the auth endpoint.- Edit the two items in
.pml-pointsto match your link expiry and device rules. - Swap the inline SVG inside
.pml-artfor your own illustration or logo.
Use cases
- SaaS and team tools: sign in with a work email and no password.
- Newsletter and membership sites: subscribers log in from the link in their inbox.
- Marketplaces and booking apps: low-friction sign in on a mobile website or PWA.
- Internal company apps built with Capacitor: email link login for staff.
Accessibility
The input has a visible label, and errors are linked with aria-describedby and aria-invalid. The countdown is not announced every second (it is not a live region), the resend toast uses role="status" and focus moves to each view's heading. The decorative illustration and icons are hidden from screen readers. All buttons are at least 44 px, focus rings are visible and the view animation is disabled under prefers-reduced-motion.