User Flows
By the end of this lesson you will be able to draw a user flow for a task, include decisions and error paths, and spot steps you can remove before designing any screen.
A user flow is a diagram of the path a person takes through a product to finish one task. It sits between research and screens. Research tells you what people need; a flow tells you which steps they will take to get it.
Why draw flows first?
Think of a dabbawala route in Mumbai. Before a single tiffin moves, the route is fixed: pick up from home, sort at the station, train to the area, hand over at the office. Every handover point is known. That is why the system works.
A user flow does the same for your app. It shows every screen, every choice and every place where something can go wrong, before you spend hours making screens look good.
Three kinds of flow diagrams
| Type | Shows | Use when |
|---|---|---|
| Task flow | One fixed path for one task, no branches | You want to count the basic steps |
| User flow | The task with decisions, branches and errors | You plan the real behaviour |
| Wireflow | Small wireframes of each screen joined by arrows | You need to show layout and flow together |
Flow shapes
Most teams use a few simple shapes. You can draw them on paper, in FigJam or in any diagram tool.
- Oval: start or end of the flow.
- Rectangle: a screen or a step.
- Diamond: a decision with yes or no (or several) answers.
- Arrow: the direction of movement.
Run this example to see the shapes built in HTML and CSS.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Flow shapes</title>
<style>
body { font-family: system-ui, sans-serif; padding: 24px; color: #1a1a2e; }
.flow { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.shape { padding: 12px 16px; border: 2px solid #5b21b6; background: #f3ecff; font-size: 14px; text-align: center; }
.oval { border-radius: 999px; }
.rect { border-radius: 4px; }
.decision { width: 80px; height: 80px; rotate: 45deg; display: grid; place-items: center; padding: 0; margin: 16px; }
.decision span { rotate: -45deg; font-size: 13px; }
.arrow { font-size: 22px; color: #4b5563; }
</style>
</head>
<body>
<div class="flow">
<div class="shape oval">Start</div>
<div class="arrow" aria-hidden="true">→</div>
<div class="shape rect">Choose doctor</div>
<div class="arrow" aria-hidden="true">→</div>
<div class="shape decision"><span>Slot free?</span></div>
<div class="arrow" aria-hidden="true">→</div>
<div class="shape rect">Confirm</div>
<div class="arrow" aria-hidden="true">→</div>
<div class="shape oval">End</div>
</div>
</body>
</html>You should see an oval, a rectangle, a diamond and arrows in one row. The diamond is a rotated square, and its text is rotated back so it reads straight.
Build a user flow step by step
Let us draw the flow for "book a clinic appointment".
Step 1: write the goal and the entry point. Goal: Sunita books a slot with Dr Mehta. Entry point: she taps a reminder SMS link. Entry points matter: someone coming from an SMS may not be logged in.
Step 2: list the happy path. The happy path is the flow when everything goes right.
Open link → Choose doctor → Choose date → Choose time → Enter phone → OTP → Confirm → BookedYou should now have eight boxes in a line. Count them: that is the minimum effort for this task.
Step 3: add decisions. Ask "what if?" at every step. Is she already logged in? Is any slot free that day? Did the OTP arrive?
Step 4: add error and edge paths. An edge case is an unusual but possible situation. Examples: no slots this week, OTP not received, payment failed, network lost halfway.
Open link
→ Logged in?
yes → Choose doctor
no → Enter phone → OTP received?
yes → Choose doctor
no → Resend OTP (after 30 s) or call clinic
Choose doctor → Choose date → Any slot free?
yes → Choose time → Confirm → Booked (SMS sent)
no → Show next free date → Choose dateStep 5: look for steps to remove. Could the date and time be one screen? Could the doctor be pre-selected from the SMS link? Every step you remove is time saved for every patient, every day.
Try the flow
This small demo walks through the same flow, including the "no slots" branch. Choose different answers to follow different paths.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Flow walk-through</title>
<style>
body { font-family: system-ui, sans-serif; padding: 16px; max-width: 380px; color: #1a1a2e; }
.screen { border: 2px solid #1a1a2e; border-radius: 16px; padding: 20px; min-height: 160px; }
.screen h1 { font-size: 18px; margin-top: 0; }
button { display: block; width: 100%; margin-top: 8px; padding: 10px; border-radius: 8px; border: 1px solid #5b21b6; background: #fff; color: #3b0d8c; font-size: 15px; }
button.primary { background: #5b21b6; color: #fff; }
#path { font-size: 13px; color: #4b5563; }
</style>
</head>
<body>
<div class="screen" id="screen"></div>
<p id="path"></p>
<script>
const steps = {
start: { title: 'Book with Dr Mehta', options: [['Choose date: Wed 18 Nov', 'checkSlot']] },
checkSlot: { title: 'Wed 18 Nov', options: [['10:30 am is free', 'confirm'], ['Pretend: no slots that day', 'noSlots']] },
noSlots: { title: 'No slots on Wed 18 Nov', options: [['Next free: Thu 19 Nov, 9:00 am', 'confirm']] },
confirm: { title: 'Confirm your visit?', options: [['Confirm booking', 'done']] },
done: { title: 'Booked. SMS sent to your phone.', options: [['Start again', 'start']] }
};
const trail = [];
function show(key) {
const step = steps[key];
trail.push(key);
const screen = document.getElementById('screen');
screen.replaceChildren();
const h = document.createElement('h1');
h.textContent = step.title;
screen.append(h);
step.options.forEach(([label, next], i) => {
const b = document.createElement('button');
b.type = 'button';
b.textContent = label;
if (i === 0) b.className = 'primary';
b.addEventListener('click', () => { if (next === 'start') trail.length = 0; show(next); });
screen.append(b);
});
document.getElementById('path').textContent = 'Path so far: ' + trail.join(' → ');
}
show('start');
</script>
</body>
</html>You should see a phone-like box with a title and buttons, and the path you have taken printed below. Try both branches. Notice that the "no slots" screen does not dead-end: it offers the next free date. A good flow never leaves a person stuck.
Common mistakes
- Drawing only the happy path. Real users meet errors every day, especially on slow networks.
- Dead ends. Every error state needs a way forward or back.
- Ignoring entry points. People arrive from SMS links, search results and shared WhatsApp links, not only from the home screen.
- Too much detail too early. Flows are for steps and decisions; leave colours and icons for later.
Key points
- A user flow shows the steps, decisions and errors in one task.
- Use ovals for start and end, rectangles for steps, diamonds for decisions.
- Draw the happy path first, then add decisions and edge cases.
- Every error path needs a clear way forward.
- Counting and removing steps is one of the cheapest ways to improve UX.
Exercise
Draw a user flow (in a text block or on paper) for paying a college fee with UPI. Include the happy path, a decision for "UPI app installed?" and an error path for "payment pending". Then edit the walk-through demo so the confirm screen has a second option, "Change time", that goes back to checkSlot.
Show solution
confirm: { title: 'Confirm your visit?', options: [['Confirm booking', 'done'], ['Change time', 'checkSlot']] },The new pair adds a second button that returns to the slot screen. A good fee flow might read: Open fee page → Check amount → Pay with UPI → UPI app installed? (no: show QR code) → Enter UPI PIN in the app → Payment status? (pending: show "We will confirm within a few minutes" and a reference number, never a second Pay button).
Quick Quiz
1. Which shape usually shows a decision in a flow diagram?
Diamonds mark points where the path splits based on an answer.
2. What is the happy path?
The happy path is the ideal route with no errors or detours.
3. Why should the "no slots" screen show the next free date?
Every error or empty state should offer a clear way forward.
Learn UI/UX Design with a mentor
Free lessons get you started. Our UI/UX Design training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
