Building Accessible Onboarding Flows with ShellApps
First impressions matter. If your signup flow is confusing, slow, or inaccessible, you've already lost users before they've seen your product.
Here's how we approach onboarding at ShellApps โ and how you can use our tools to build something better.
Start with the Basics
A good onboarding flow does three things well:
- Collects only what's needed โ Name, email, password. Everything else can wait.
- Provides immediate feedback โ Inline validation, clear error messages, progress indicators.
- Works for everyone โ Keyboard navigation, screen reader support, high contrast, responsive layout.
Building It with ShellApps Identity
The Registration Form
ShellApps Identity handles the backend โ registration, email verification, session management. Your job is the form itself.
Here's a React example using our SDK:
import { useState } from 'react';
function SignupForm() {
const [form, setForm] = useState({ name: '', email: '', password: '' });
const [errors, setErrors] = useState({});
const handleSubmit = async (e) => {
e.preventDefault();
const res = await fetch('/api/auth/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(form),
});
const data = await res.json();
if (!res.ok) setErrors({ form: data.message });
};
return (
<form onSubmit={handleSubmit} aria-label="Create account">
<label htmlFor="name">Full name</label>
<input
id="name"
type="text"
required
autoComplete="name"
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
/>
{/* email and password fields follow the same pattern */}
<button type="submit">Create account</button>
{errors.form && <p role="alert">{errors.form}</p>}
</form>
);
}
Key Accessibility Patterns
Labels, not placeholders. Placeholders disappear when you start typing. Labels don't. Every input needs a visible <label> with a matching htmlFor.
Error announcements. Use role="alert" on error messages so screen readers announce them immediately. Don't just turn the border red โ say what's wrong in plain text.
Logical tab order. Users who navigate by keyboard expect to move through the form top to bottom. Don't rearrange visual order with CSS without updating the DOM order.
Autocomplete attributes. Adding autoComplete="email" and autoComplete="new-password" lets browsers and password managers help your users. It's one attribute that saves real time.
Email Verification
After registration, ShellApps Identity sends a verification email with a 6-digit code. Design your verification screen to be:
- Forgiving โ Let users paste the code, not just type digit-by-digit
- Recoverable โ Offer a "resend code" button with a cooldown timer
- Patient โ Don't expire codes after 60 seconds. We use 10-minute windows by default
Measuring Onboarding Success
Use Experience Platform's event tracking to measure drop-off at each step:
client.track('onboarding_step', { step: 'registration_started' });
client.track('onboarding_step', { step: 'email_verified' });
client.track('onboarding_step', { step: 'profile_completed' });
Build a funnel in the analytics dashboard to see where users get stuck. Fix the biggest drop-off first, then iterate.