UI/UX Design Module 10 – Content design and UX writing
UX writing: plain language, voice, structure
Write interface text in plain language, keep one voice while the tone follows the moment, put key words first, and know what readability scores miss.
What you will learn
- Write interface text in plain language for the reader's task
- Define a product voice and choose the tone each moment needs
- Structure text for scanning, with the key words first in headings, links and buttons
- Check text with readability, passive-voice and inclusive-language tools, and explain what they miss
Before you start
What you’ll learn · Before you start
What you will learn
- Write interface text in plain language for the reader's task
- Define a product voice and choose the tone each moment needs
- Structure text for scanning, with the key words first in headings, links and buttons
- Check text with readability, passive-voice and inclusive-language tools, and explain what they miss
Before you start
On this page
MealBox’s notice about pausing a plan, written for this lesson, was one sentence of 43 words, with four passive verbs and the deadline buried in the middle. Rewritten in four moves it says the same thing in 18 words, and it opens with the action and the deadline: “Pause at least 48 hours”.
UX writing: Writing the words of an interface, such as labels, buttons, messages and help, so that people can use the product. It is part of content design. is the work of choosing those words: labels, buttons, messages and help. You will rewrite text in plain language, keep one voice while the tone follows the moment, put the key words first for people who scan, and use readability, passive-voice and inclusive-language checks for what they are good at, knowing what they miss.
Plain language starts from the reader’s task, not from short words
The pause notice failed in a way any reader can feel: by the time the sentence reached “48 hours”, the reader had passed “a temporary suspension of your subscription” and “a request must be submitted by you”. Nothing in it was false. It was written from the company’s side, in the company’s words.
plain language: Writing that its intended readers can find, understand and act on the first time. It is written for their task and knowledge, which can include technical terms, not simplified for an imagined reader. is writing that the intended reader can find, understand and act on the first time. The US Plain Writing Act of 2010 defines plain writing as writing that is “clear, concise, well-organized” and suited to the intended audience. Digital.gov, which publishes the US government’s plain language guides, calls “write for your audience” the first rule, and counts the idea that plain language means dumbing text down among the common myths. Write for what the reader knows and needs to do, which may be technical.
Four moves do most of the work. Use the reader’s words. Say who does what, in the active voice: A sentence whose subject is the person or thing that acts: 'we will send your delivery' rather than 'your delivery will be sent'. It makes clear who does what.; digital.gov notes that the passive can be right in a few cases, such as a step that follows from a law with no one else acting. Put the action first. Cut what the reader skips. Step through them on the pause notice:
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- The draft. "Please be advised that in the event that a temporary suspension of your subscription is required, a request must be submitted by you…" One sentence of 43 words, four passive verbs, and the deadline in the middle.
- Use the reader's words. Customers say "pause my plan", not "temporary suspension of my subscription", and "next delivery", not "the scheduled delivery". Swapping in their words cuts 7 words and one passive verb.
- Say who does what. "A request must be submitted by you" becomes "you must ask", and "the delivery will be processed and charged" becomes "we will send the delivery and charge you". Each sentence now names the person who acts.
- Put the action first. "To pause your plan, ask at least 48 hours before your next delivery." The goal opens the sentence, the opening formula goes, and the warning moves to a second sentence of its own.
- Cut what the reader skips. "Pause at least 48 hours before your next delivery, or we send it and charge you as usual." 18 words, 58 % fewer than the draft, and the one fact that matters, 48 hours, is still there.
The program applies the same four moves and counts what each one changed. It flags passive verbs the way digital.gov describes them, a form of “to be” followed by a past participle, and the words that MealBox’s own research found its customers never use:
# One MealBox message rewritten in four moves. For each version the program counts words, the longest sentence, passive
# verbs (a form of "to be" followed by a past participle, the pattern digital.gov describes) and words the team's research
# found customers never use. The message and the word list are invented for this lesson.
import re
VERSIONS = [
("Draft", "Please be advised that in the event that a temporary suspension of your subscription is required, "
"a request must be submitted by you no later than 48 hours prior to the scheduled delivery, otherwise "
"the delivery will be processed and charged as normal."),
("Reader's words", "Please be advised that if you need to pause your plan, a request must be submitted by you at "
"least 48 hours before your next delivery, otherwise the delivery will be processed and charged "
"as normal."),
("Active voice", "Please be advised that if you need to pause your plan, you must ask at least 48 hours before "
"your next delivery, otherwise we will send the delivery and charge you as normal."),
("Key words first", "To pause your plan, ask at least 48 hours before your next delivery. Otherwise we send the "
"delivery and charge you as normal."),
("Cut the rest", "Pause at least 48 hours before your next delivery, or we send it and charge you as usual."),
]
NOT_THEIR_WORDS = {"advised", "suspension", "subscription", "submitted", "prior", "scheduled", "processed", "event"}
BE = r"(?:is|are|was|were|be|been|being)"
PARTICIPLE = r"\w+(?:ed|en)"
def words(text):
return re.findall(r"[A-Za-z0-9']+", text)
def sentences(text):
return [s for s in re.split(r"(?<=[.!?])\s+", text.strip()) if s]
for name, text in VERSIONS:
longest = max(len(words(s)) for s in sentences(text))
passive = re.findall(rf"\b{BE}\s+(?:\w+\s+)?{PARTICIPLE}\b", text, flags=re.IGNORECASE)
jargon = sorted({w.lower() for w in words(text)} & NOT_THEIR_WORDS)
print(f"{name}: {len(words(text))} words, longest sentence {longest}")
print(f" passive: {', '.join(passive) or 'none'}")
print(f" not their words: {', '.join(jargon) or 'none'}")
first, last = len(words(VERSIONS[0][1])), len(words(VERSIONS[-1][1]))
print(f"\n{first} words became {last}, {100 * (first - last) / first:.0f} % fewer, and the deadline survived every move:")
result = all("48 hours" in text for _, text in VERSIONS)
print("48 hours in every version:", result) Output
Draft: 43 words, longest sentence 43 passive: be advised, is required, be submitted, be processed not their words: advised, event, prior, processed, scheduled, submitted, subscription, suspension Reader's words: 36 words, longest sentence 36 passive: be advised, be submitted, be processed not their words: advised, processed, submitted Active voice: 33 words, longest sentence 33 passive: be advised not their words: advised Key words first: 23 words, longest sentence 13 passive: none not their words: none Cut the rest: 18 words, longest sentence 18 passive: none not their words: none 43 words became 18, 58 % fewer, and the deadline survived every move: 48 hours in every version: True
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 rewrite.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
The draft carries 43 words, four passive verbs and eight words customers do not say. The last version has 18 words and none of either. The last line of the output matters as much as the others: every version still says 48 hours, so no move cut the one fact the reader needs.
Cutting a fact along with the words
Wrong: “Pause before your next delivery”, which is shorter but drops the deadline, so people pause too late and are charged. Right: “Pause at least 48 hours before your next delivery”. Shorter is the means; the reader acting correctly is the goal, so check that every fact survives each cut.
Checkpoint
Check: Plain language for the reader's task
One voice, and a tone for each moment
MealBox once showed “Oops, our bad, lunch is on hold” when a card payment failed. Customers wrote in to ask whether they had been charged. The joke was harmless on a confirmation screen and wrong on a payment failure, although the same writer wrote both in the same voice.
A voice: A product's character in words: its vocabulary, its formality and how it speaks to people. The voice stays the same on every screen, while the tone changes with the moment. is the product’s character in words, and it stays the same everywhere. Apple’s writing guidance starts by asking teams to determine their app’s voice, then to match the tone: How a product's voice speaks at a given moment, such as warm, brief or serious. It moves with the reader's situation along scales such as humour, formality, respectfulness and enthusiasm. to the context: what people are doing in the app and in the world around it. Nielsen Norman Group describes tone along four dimensions, humour, formality, respectfulness and enthusiasm, each a scale rather than a switch. GOV.UK goes further for services: avoid humorous error messages, because people often use a service when they are under stress.
MealBox’s voice is plain, warm and direct. Its tone moves along those dimensions with the moment:
| Moment | Tone | What MealBox says |
|---|---|---|
| First delivery booked | Warm | Your first box arrives tomorrow between 12 and 1. |
| Payment failed | Serious, direct | Your bank declined the card. Add another card to keep tomorrow’s lunch. |
| Plan paused | Neutral, brief | Plan paused. No deliveries until you restart. |
| A field left empty | Calm, exact | Enter a phone number with 10 digits. |
The same choice can be made for any message by asking three questions about the moment. Answer them in the table, for the payment failure first and then for the first delivery, and watch which tones still fit:
Answer the questions above: the table then marks what fits your case and says why the rest does not.
| Tone | Reader under stress | Money or data at stake | Seen many times | Something went well |
|---|---|---|---|---|
| Playful Sounds like: a joke about lunch | Poor a joke reads as not listening when someone is worried or rushed | Poor humour next to a failed payment makes people doubt what happened | Poor a pun that charms once grates by the tenth time | Good a first delivery or a finished plan can carry some fun |
| Warm Sounds like: a friend who helps | Mixed kind words help only if the fix comes first | Mixed fine if the facts are exact: amount, date and what to do | Mixed keep it short, or the warmth turns into padding | Good suits a welcome or a thank-you |
| Neutral and brief Sounds like: a clear label | Good says what happened and what to do, with nothing to read past | Good exact and calm: the amount, the card, the next step | Good labels and status lines people read daily stay easy to skip | Mixed correct, but can feel flat after a big step |
| Serious and direct Sounds like: careful, exact words | Good right for a payment failure or a problem with safety | Good names the risk and the action without softening them | Poor too heavy for routine text, so people stop reading it | Poor sounds like a warning when nothing is wrong |
How the answers decide
- “Could the reader be worried, rushed or upset at this moment?” Yes, it may be a bad moment: rules out Playful and adds a caveat to Warm. Someone who is worried wants to know what happened and what to do. A joke reads as not listening, and warmth helps only after the fix is clear.
- “Is money, health or personal data involved in this message?” Yes, something is at stake: rules out Playful. Where money, health or data is at stake, people need exact facts: what happened, how much, and the next step. Humour makes them doubt the message.
- “Will the same person read this text many times, such as a label or a daily status?” Yes, it is routine text: rules out Serious and direct and adds a caveat to Playful and Warm. Routine text is read many times. Heavy words make people stop reading it, and charm wears out, so keep it brief.
- “Could the reader be worried, rushed or upset at this moment?” No, nothing is wrong and “Is money, health or personal data involved in this message?” No, nothing is at stake and “Will the same person read this text many times, such as a label or a daily status?” No, it appears once or rarely: adds a caveat to Serious and direct. With nothing wrong and nothing at stake, a serious tone sounds like a warning. A rare happy moment can be warm or even playful.
A payment failure rules out the playful tone twice: the reader may be worried and money is at stake. A rare happy moment leaves every tone open, with a caveat on the serious one, which sounds like a warning when nothing is wrong. Routine text, such as a status shown every day, keeps to neutral and brief.
Key idea
The voice says who is speaking and never changes; the tone says how they speak right now, and the reader’s moment decides it.
Checkpoint
Check: One voice, a tone per moment
Readers scan, so the key words go first
Ward Desk’s help page listed links such as “Click here to report a broken streetlight” and “Learn more”. None of its eight links started with the word a resident would scan for, so someone looking for streetlights could not tell the links apart by their first words. GOV.UK’s guidance for services is blunt about why that fails: people scan rather than read, especially in a task, so put the important words first and drop the words they do not need.
Nielsen Norman Group measured how little a scan takes in. Its test gave people only the first 11 characters of each link, about two words, which is how much of a list item a scanning reader usually sees. Screen reader users scan too, by structure: in WebAIM’s eleventh survey of screen reader users, with 1,780 responses, 67.8 % said they move through the headings first when looking for information on a long page, and 88.3 % found heading levels very or somewhat useful. The sample was not controlled, so take the numbers as a strong signal, not a census. GOV.UK adds that screen reader users often hear a list of links on its own, so “click here” tells them nothing.
front-loading: Putting the words a reader is looking for at the start of a heading, link, button or sentence, because people scanning a page read only the first words of each item. means putting the word the reader is scanning for at the start of a heading, link or button. The program checks eight Ward Desk links before and after a rewrite, using the same 11-character lead:
# What a scanning reader gets from the start of each Ward Desk link: its first 11 characters, about two words, the size
# of the lead Nielsen Norman Group tested. The links and their key words are invented for this lesson.
LINKS = [
# (before, after, the word a resident is scanning for)
("Click here to report a broken streetlight", "Streetlight broken: report it", "streetlight"),
("Information about checking the status of a complaint", "Complaint status", "complaint"),
("If you want to change your contact details, go here", "Contact details: change them", "contact"),
("Frequently asked questions about blocked drains", "Blocked drains: questions", "drains"),
("Please read our guidance before uploading photos", "Photos: size and format rules", "photos"),
("Learn more", "Rubbish collection days", "rubbish"),
("Our commitment to accessibility", "Accessibility statement", "accessibility"),
("Ward Desk form for reporting water supply problems", "Water supply: report a problem", "water"),
]
LEAD = 11
def found_in_lead(text, word):
return word in text[:LEAD].lower() or text.lower().startswith(word[:LEAD])
hits_before = hits_after = 0
for before, after, word in LINKS:
b, a = found_in_lead(before, word), found_in_lead(after, word)
hits_before += b
hits_after += a
print(f"{word}:")
print(f" before '{before[:LEAD]}' {'found' if b else 'missing'}")
print(f" after '{after[:LEAD]}' {'found' if a else 'missing'}")
print(f"\nKey word inside the first {LEAD} characters: {hits_before} of {len(LINKS)} before, {hits_after} of {len(LINKS)} after")
lengths = [len(after) for _, after, _ in LINKS]
summary = f"Rewritten links: {min(lengths)} to {max(lengths)} characters"
print(summary) Output
streetlight: before 'Click here ' missing after 'Streetlight' found complaint: before 'Information' missing after 'Complaint s' found contact: before 'If you want' missing after 'Contact det' found drains: before 'Frequently ' missing after 'Blocked dra' missing photos: before 'Please read' missing after 'Photos: siz' found rubbish: before 'Learn more' missing after 'Rubbish col' found accessibility: before 'Our commitm' missing after 'Accessibili' found water: before 'Ward Desk f' missing after 'Water suppl' found Key word inside the first 11 characters: 0 of 8 before, 7 of 8 after Rewritten links: 16 to 30 characters
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 front_load.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
No old link puts its key word in the lead; seven of the eight rewrites do. The one miss is instructive: “Blocked drains” reads well, yet the scan stops at “Blocked dra”, before the word residents look for.
Fix the last link
Press Edit, change “Blocked drains: questions” to “Drains: blocked or flooded” and run it again. The count reaches 8 of 8, and the link still says what the page covers.
The same rule gives a whole page its structure, with the key information at the top: one idea per sentence, headings that describe what follows, and lists for steps or choices, which digital.gov recommends for detail that would otherwise overload readers. Write the real words before the layout is fixed. W3C’s article on text size in translation shows that translated text is usually longer than English, and that the shorter the source, the larger the expansion can be, which is the text expansion: The tendency of text to grow in length when translated, often most for short source strings, so a label that fits in one language may overflow in another. a layout must leave room for.
Checkpoint
Check: Key words first for scanning
Readability scores estimate difficulty; readers measure it
A MealBox manager asked for a number to prove the refund help was easier after its rewrite. A readability formula: A formula that estimates how hard a text is to read from counts such as words per sentence and syllables per word. It cannot see meaning, order or accuracy. gives one, such as Rudolph Flesch’s 1948 Flesch reading ease: Rudolph Flesch's 1948 score: 206.835 minus 1.015 times the words per sentence minus 84.6 times the syllables per word. Higher means easier; English text only.. It reads only two things: how long the sentences are and how long the words are.
In words: start from 206.835, take away about one point for each word in an average sentence, and 84.6 points for each syllable in an average word. A passage of 10-word sentences with 1.5 syllables a word scores 206.835 − 10.15 − 126.9 = 69.8. Higher is easier, and the Flesch–Kincaid grade turns the same two ratios into a US school grade. The program scores five MealBox texts before and after rewriting, with syllables estimated from vowel groups:
# Flesch Reading Ease (Flesch 1948) and the Flesch-Kincaid grade for five MealBox messages, before and after a rewrite.
# Syllables are estimated by counting vowel groups, so scores can differ by a few points from a tool that uses a
# dictionary. The messages are invented for this lesson.
import re
PAIRS = [
("Paused plan",
"Your subscription has been temporarily suspended pending verification of your payment information.",
"We paused your plan. Check your card details to restart it."),
("Delivery change",
"Modifications to delivery preferences are effective from the subsequent delivery cycle.",
"Changes start from your next delivery."),
("Wrong code",
"An authentication failure occurred. Please reinitiate the verification procedure.",
"That code did not work. Ask for a new code."),
("Address check",
"Kindly ensure that the delivery address provided is accurate and complete prior to confirmation.",
"Check your address before you confirm."),
("Refund help",
"In order to facilitate the efficient processing of your refund request, it is necessary that the relevant "
"order reference number be provided. This information can be located within the confirmation communication "
"that was dispatched to your registered email address at the time of purchase. Requests lacking this "
"information will not be processed.",
"To get a refund, give us your order number. You can find it in the confirmation email we sent when you "
"ordered. We cannot refund an order without it."),
]
def syllables(word):
w = word.lower()
if not w.isalpha():
return 1
groups = len(re.findall(r"[aeiouy]+", w))
if w.endswith("e") and not w.endswith(("le", "ee")) and groups > 1:
groups -= 1
if w.endswith(("es", "ed")) and not w.endswith(("ted", "ded", "ses", "zes", "ces", "ges")) and groups > 1:
groups -= 1
return max(1, groups)
def scores(text):
sents = [s for s in re.split(r"(?<=[.!?])\s+", text.strip()) if s]
words = re.findall(r"[A-Za-z0-9']+", text)
syl = sum(syllables(w) for w in words)
wps, spw = len(words) / len(sents), syl / len(words)
ease = 206.835 - 1.015 * wps - 84.6 * spw
grade = 0.39 * wps + 11.8 * spw - 15.59
return ease, grade, len(words)
for name, before, after in PAIRS:
eb, gb, nb = scores(before)
ea, ga, na = scores(after)
print(f"{name}: ease {eb:.1f} -> {ea:.1f}, grade {gb:.1f} -> {ga:.1f}, words {nb} -> {na}")
text = PAIRS[1][2]
shuffled = " ".join(reversed(text.rstrip(".").split())) + "."
print(f"\nSame words, reversed: '{shuffled}'")
same = scores(text)[0] == scores(shuffled)[0]
print(f"Ease {scores(text)[0]:.1f} and {scores(shuffled)[0]:.1f}: the formula cannot tell them apart ({same})") Output
Paused plan: ease -9.8 -> 101.3, grade 17.6 -> 0.5, words 12 -> 11 Delivery change: ease -27.4 -> 59.7, grade 19.8 -> 6.4, words 11 -> 6 Wrong code: ease -13.9 -> 117.2, grade 16.3 -> -1.8, words 9 -> 10 Address check: ease 23.4 -> 73.8, grade 13.5 -> 4.5, words 14 -> 6 Refund help: ease 29.8 -> 77.4, grade 13.4 -> 4.9, words 52 -> 29 Same words, reversed: 'delivery next your from start Changes.' Ease 59.7 and 59.7: the formula cannot tell them apart (True)
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 readability.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
The refund help rose from 29.8 to 77.4 and fell from 52 to 29 words, the kind of passage the formula was made for. The one-line strings show its limits. Their scores run off both ends of the scale, from −27.4 to 117.2, and “Changes start from your next delivery”, as plain as a sentence gets, scores 59.7 because one four-syllable word weighs heavily in six words. The last line is the deepest limit: the same words in reverse order score exactly the same, so the formula cannot see order, meaning or accuracy. Its weights were also fitted to English text, so the score means nothing for a Hindi string.
inclusive language: Words that do not exclude or demean people, avoiding ableist phrases, gendered defaults and idioms that many readers will not understand or that will not translate. checks have a similar shape. They flag the kinds of words Apple’s inclusion guidance warns about: idioms that will not translate, phrases that use a disability to mean something bad, such as “blind to” or “crazy”, and gendered defaults, where GOV.UK suggests “they” instead of “he or she”. A flag is a question for a person, not a verdict. MySmartCoPilot’s Readability Checker, Passive Voice Checker and Inclusive Language Checker each run one such check on your own text.
What measures clarity is a reader. Digital.gov describes paraphrase testing for short pages, where a person says in their own words what the text means, and usability testing for longer content and forms. It asks teams to start testing early, revise and test again, at least twice.
Key idea
A readability score is a cheap first check on sentence and word length; whether a reader understands and acts correctly is measured only by testing with readers.
Checkpoint
Check: What readability scores and checks measure
Practise
Ward Desk’s help page about reporting a streetlight needs the treatment this lesson describes. Rewrite its heading, its paragraphs and five interface strings so that the sample tests pass: the same simple counts as the examples, plus limits for each kind of string.
Exercise · Easy · Python
Rewrite a Ward Desk help page and five strings
Ward Desk's help page about reporting a broken streetlight is in solution.py: a heading, two paragraphs and five interface strings. Rewrite the text so that:
- Facts: every phrase in
FACTSstill appears in the heading or the paragraphs. - Plain paragraphs: no sentence is longer than 20 words, no sentence uses a passive verb (a form of "to be" followed by a word ending in -ed or -en), and the paragraphs together score at least 60 on Flesch reading ease, counted the way the lesson's example counts it.
- Key words first: the heading is at most 60 characters and does not start with a filler word such as "Information", "About" or "Welcome".
- Strings: buttons and error messages start with a verb that names the action (see
ACTION_VERBSin the tests); buttons are at most 24 characters, labels at most 30, links at most 40 and errors at most 80; no link says only "click here", "learn more", "here" or "read more". - No flagged words: none of the phrases in
FLAGGEDin the tests appears anywhere.
Keep the five strings in their order and with their kinds. Change only the text.
Starter code · solution.py
"""
Ward Desk's help page for reporting a broken streetlight, and five interface strings, written for this exercise.
Rewrite HEADING, PARAGRAPHS and the text of each string in STRINGS so that the sample tests pass.
Keep every phrase of FACTS somewhere in the heading or the paragraphs.
"""
FACTS = ["24 hours", "pole number", "photo"]
HEADING = "Information regarding the procedure for the reporting of streetlight faults"
PARAGRAPHS = [
"In the event that a streetlight in your area is observed to be non-functional, a report may be submitted "
"through Ward Desk, and it is requested that the pole number, which is located on a metal plate affixed to "
"the pole, be included in the report.",
"Reports that are received will be processed by the electrical department within 24 hours, and residents are "
"encouraged to attach a photo, which will facilitate the identification of the fault by maintenance personnel.",
]
# (kind, text): kind is one of button, link, error, label
STRINGS = [
("button", "Click here to submit your report"),
("button", "Proceed"),
("link", "Learn more"),
("error", "Invalid input. Please try again"),
("label", "Pole identification number (as displayed on the pole)"),
] The sample tests · test_solution.py
"""Sample tests for the rewrite-ward-desk-help exercise. The counts match the lesson's examples."""
import re
from solution import FACTS, HEADING, PARAGRAPHS, STRINGS
KINDS = ["button", "button", "link", "error", "label"]
LIMITS = {"button": 24, "label": 30, "link": 40, "error": 80}
ACTION_VERBS = {"add", "call", "cancel", "change", "check", "choose", "edit", "enter", "find", "give", "pause",
"remove", "report", "restart", "save", "send", "upload"}
FILLER_STARTS = {"information", "about", "welcome", "introduction", "click", "please", "the", "a", "an"}
VAGUE_LINKS = {"click here", "learn more", "here", "read more"}
FLAGGED = ["click here", "please be advised", "kindly", "simply", "obviously", "invalid", "crazy", "insane",
"lame", "dumb", "he or she", "guys"]
BE = r"(?:is|are|was|were|be|been|being)"
def syllables(word):
w = word.lower()
if not w.isalpha():
return 1
groups = len(re.findall(r"[aeiouy]+", w))
if w.endswith("e") and not w.endswith(("le", "ee")) and groups > 1:
groups -= 1
if w.endswith(("es", "ed")) and not w.endswith(("ted", "ded", "ses", "zes", "ces", "ges")) and groups > 1:
groups -= 1
return max(1, groups)
def sentences(text):
return [s for s in re.split(r"(?<=[.!?])\s+", text.strip()) if s]
def words(text):
return re.findall(r"[A-Za-z0-9']+", text)
def ease(text):
sents, ws = sentences(text), words(text)
return 206.835 - 1.015 * len(ws) / len(sents) - 84.6 * sum(syllables(w) for w in ws) / len(ws)
def test_every_fact_survives():
page = (HEADING + " " + " ".join(PARAGRAPHS)).lower()
missing = [f for f in FACTS if f.lower() not in page]
assert not missing, f"facts missing from the page: {missing}"
def test_sentences_of_20_words_or_fewer():
long = [s for p in PARAGRAPHS for s in sentences(p) if len(words(s)) > 20]
assert not long, f"{len(long)} sentence(s) over 20 words, the first: '{long[0][:60]}…'" if long else ""
def test_no_passive_verbs():
found = [m.group(0) for p in PARAGRAPHS for m in re.finditer(rf"\b{BE}\s+(?:\w+\s+)?\w+(?:ed|en)\b", p, re.I)]
assert not found, f"passive verbs: {found}"
def test_reading_ease_at_least_60():
score = ease(" ".join(PARAGRAPHS))
assert score >= 60, f"reading ease {score:.1f}, below 60"
def test_heading_puts_the_key_word_first():
assert len(HEADING) <= 60, f"heading is {len(HEADING)} characters"
first = words(HEADING)[0].lower()
assert first not in FILLER_STARTS, f"the heading starts with '{first}'"
def test_strings_keep_their_kinds():
assert [k for k, _ in STRINGS] == KINDS, "keep the five strings in their order and with their kinds"
def test_string_lengths():
over = [(k, t, len(t)) for k, t in STRINGS if len(t) > LIMITS[k]]
assert not over, f"over the limit for its kind: {over}"
def test_buttons_and_errors_start_with_an_action():
for kind, text in STRINGS:
if kind in ("button", "error"):
first = words(text)[0].lower()
assert first in ACTION_VERBS, f"{kind} '{text}' starts with '{first}', not an action verb"
def test_links_say_where_they_go():
vague = [t for k, t in STRINGS if k == "link" and t.strip(" .").lower() in VAGUE_LINKS]
assert not vague, f"links that say nothing out of context: {vague}"
def test_no_flagged_words():
everything = " ".join([HEADING, *PARAGRAPHS, *(t for _, t in STRINGS)]).lower()
hits = [f for f in FLAGGED if re.search(rf"\b{re.escape(f)}\b", everything)]
assert not hits, f"flagged: {hits}" A hint
Start with the paragraphs. Split each long sentence into two or three, and give each one a person who acts: "Report a broken streetlight", "The electrical team visits", "Add a photo". Then check that 24 hours, the pole number and the photo are all still there.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Then take the questions, which start from the idea you have answered least well:
Practice that adapts to you
Practise this lesson
13 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Warm-up: how do voice and tone differ in interface writing?
Voice is who the product is in words: its vocabulary, how formal it is, whether it says “we” and “you”. It stays the same on every screen, so the product sounds like one thing. Tone is how that voice speaks at a given moment, and it moves with the reader’s situation: lighter for a first delivery, brief for a routine status, serious and exact for a failed payment. A useful way to show it is a chart with one voice and a few moments, each with its tone and an example line, because a team can then check a new message against it instead of arguing about taste.
Warm-up: why put the important words first in a heading, link or button?
Because people scan. They read the start of each heading or link and decide from that whether to keep reading, and a screen reader user who moves through a list of links or headings hears each one out of context. If the start is “Click here” or “Information about”, every item begins the same and the reader learns nothing. Starting with the word they are looking for, such as “Streetlight broken: report it”, lets the eye or the ear stop at the right item.
Two harder questions follow. Decide what you would want to know before changing a single word, then open either:
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Mid to senior
Ward Desk's legal team insists that the help text on its noise complaint form quotes the city bylaw word for word, in a 70-word sentence. Research shows residents misread who may complain and when. How do you work with legal to fix the page?
-
Mid to staff
MealBox's release pipeline blocks any interface string scoring under 70 on Flesch reading ease. Its first run blocks "Changes start from your next delivery" and 140 other strings, most of them a single line. The product manager still wants a quality gate. What should it check instead, and how would you show that it works?
Flashcards · 8 cards
Recall it, then check
Say the answer to yourself before you look: recalling it is what makes it stick.
-
What is plain language?
Writing that the intended reader can find, understand and act on the first time. It is written for what the reader knows and needs to do, which may be technical, so it is not dumbing text down.
-
Which four moves do most of the work of plain language?
Use the reader's words, say who does what in the active voice, put the action first, and cut what the reader skips. Then check that every fact survives the cuts: a shorter pause notice that drops the 48-hour deadline gets people charged.
-
What is the difference between a product's voice and its tone?
The voice is the product's character in words and stays the same everywhere. The tone is how it speaks right now, and the reader's moment decides it: never playful when someone may be worried or money is at stake.
-
Along which four dimensions does Nielsen Norman Group describe tone?
Humour, formality, respectfulness and enthusiasm, each a scale rather than a switch. GOV.UK adds that services avoid humorous error messages, because people often use a service under stress.
-
What is front-loading, and why does it matter?
Putting the word the reader is scanning for at the start of a heading, link or button. People scan rather than read, and a scanning reader usually takes in only about the first 11 characters of a link, about two words.
-
What does a readability formula such as Flesch reading ease measure?
Only how long the sentences are and how long the words are; higher is easier, and 10-word sentences of 1.5 syllables a word score 69.8. It cannot see order, meaning or accuracy: the same words in reverse order score exactly the same.
-
Where are readability scores unreliable?
On one-line strings, whose scores run off both ends of the scale, and on other languages, because the weights were fitted to English text. A score means nothing for a Hindi string.
-
What measures whether interface text is clear?
Readers. Paraphrase testing asks a person to say in their own words what a short text means, and usability testing covers longer content and forms; test early, revise and test again, at least twice. A flag from a checker is a question for a person, not a verdict.
Key takeaways
- Plain language is written for the reader’s task and knowledge, using their words, the active voice, the action first and no words they would skip, and every fact survives the cuts.
- A product has one voice everywhere, and its tone moves with the reader’s moment: never playful when someone is worried or money is at stake.
- Readers scan headings, links and buttons by their first words, so the word they are looking for goes first, and link text makes sense on its own.
- Readability formulas count only sentence and word length, so they cannot see order, meaning or accuracy, and they are unreliable on one-line strings and other languages.
- Tools flag candidates for a person to judge, and paraphrase and usability tests with readers measure whether the words work.
Terms in this lesson
- active voice
- A sentence whose subject is the person or thing that acts: 'we will send your delivery' rather than 'your delivery will be sent'. It makes clear who does what.
- Flesch reading ease
- Rudolph Flesch's 1948 score: 206.835 minus 1.015 times the words per sentence minus 84.6 times the syllables per word. Higher means easier; English text only.
- front-loading
- Putting the words a reader is looking for at the start of a heading, link, button or sentence, because people scanning a page read only the first words of each item.
- inclusive language
- Words that do not exclude or demean people, avoiding ableist phrases, gendered defaults and idioms that many readers will not understand or that will not translate.
- plain language
- Writing that its intended readers can find, understand and act on the first time. It is written for their task and knowledge, which can include technical terms, not simplified for an imagined reader.
- readability formula
- A formula that estimates how hard a text is to read from counts such as words per sentence and syllables per word. It cannot see meaning, order or accuracy.
- tone
- How a product's voice speaks at a given moment, such as warm, brief or serious. It moves with the reader's situation along scales such as humour, formality, respectfulness and enthusiasm.
- UX writing
- Writing the words of an interface, such as labels, buttons, messages and help, so that people can use the product. It is part of content design.
- voice
- A product's character in words: its vocabulary, its formality and how it speaks to people. The voice stays the same on every screen, while the tone changes with the moment.
References
- Plain language guide series (Digital.gov (US General Services Administration))
- Principles of plain language (Digital.gov (US General Services Administration))
- Writing with plain language (Digital.gov (US General Services Administration))
- Testing your content (Digital.gov (US General Services Administration))
- Plain Writing Act of 2010 (Public Law 111-274) (US Government Publishing Office)
- Writing for user interfaces (Government Digital Service (GOV.UK))
- Writing (Apple)
- The Four Dimensions of Tone of Voice (Nielsen Norman Group)
- First 2 Words: A Signal for the Scanning Eye (Nielsen Norman Group)
- Screen Reader User Survey #11 Results (WebAIM)
- Text size in translation (W3C Internationalization)
- A new readability yardstick (Journal of Applied Psychology 32(3), 221-233) (American Psychological Association)
- Get your document's readability and level statistics in Microsoft Word (Microsoft)
- Derivation of new readability formulas (Automated Readability Index, Fog Count and Flesch Reading Ease Formula) for Navy enlisted personnel (Institute for Simulation and Training, University of Central Florida)
- Design for understanding (Digital.gov (US General Services Administration))
- Inclusion (Apple)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress