Name fields that assume first and last
A customer with one name cannot complete signup, because “Last name” is required. A Japanese customer’s name arrives reversed on the invoice. A Spanish customer’s second family name is silently dropped. An Indonesian customer types their single name into “First name” and receives email addressed to nobody.
The form asked two questions. Its author believed everyone has exactly two names, in a fixed order, and that the second one is the family one.
Root cause: the split encodes one culture’s convention as a data model
A given-name and family-name pair is a reasonable description of naming in part of the world and a poor description elsewhere. Four patterns break it, and each is normal for a large population.
Mononyms. A single name is the complete legal name for many people, particularly in Indonesia, and a required second field simply blocks them.
Family name first. Japanese, Chinese, Korean and Hungarian names are conventionally written family name first. A form labelling its fields by position rather than by role gets the parts swapped, and a form labelling them by role still has to decide the display order.
Multiple family names. Spanish and Portuguese naming commonly carries two inherited surnames, and a single family-name field forces the person to drop one.
Patronymics. In several traditions the second name identifies a parent rather than a family, so recording it as a surname is factually wrong and produces odd results wherever it is used as one.
Add to that the particles — van, de, bin, al- — whose treatment in sorting differs by country even within Europe, and it becomes clear that the split does not simplify anything. It moves the complexity from the data into a rule nobody wrote down.
Minimal reproducible example
<input name="firstName" required placeholder="First name" />
<input name="lastName" required placeholder="Last name" />
// The other half of the assumption, further downstream
const [first, last] = fullName.split(' '); // wrong for three-word names
const initials = `${first[0]}${last[0]}`; // throws on a mononym
const greeting = `Dear ${first},`; // wrong name in half the world
The fix: one field, and a second only for a stated reason
<label htmlFor="name">{t('form.name.label')}</label>
<input
id="name"
name="name"
autocomplete="name"
required
aria-describedby="name-hint"
/>
<span id="name-hint">{t('form.name.hint')}</span> {/* "As you would like it written" */}
One field, one standard autocomplete token, no assumption about structure. The hint states what you want rather than implying a shape.
A second field is justified when an external system genuinely requires a particular form — a payment network needing the name as printed on a card, an airline needing the name as it appears in a passport, a legal document with defined fields. In those cases the field is labelled by that purpose, not as “last name”, and it exists in addition to the display name rather than instead of it.
Sorting, greeting and initials without a surname
Three downstream uses are usually cited as the reason a split is needed, and each has a better answer.
Sorting. A locale-aware collator over the whole name produces a stable, reasonable order without any structural assumption, and it handles particles and accents correctly — the mechanism described in Unicode text handling and collation. Where a specific sort key is genuinely required — an alphabetical directory in a country with strong conventions — ask for it as its own optional field rather than deriving it.
Greeting. Addressing someone by a fragment of their name is a cultural judgement that no algorithm makes well. The robust answer is a separate, optional preferred-name field: “What should we call you?” That is one small question that removes an entire class of wrong-sounding email, and it is also the field a person can use to state a name that differs from their legal one.
Initials and avatars. Take the first grapheme cluster of the whole name and stop. Taking one from each of two fields fails for a mononym and produces nonsense for a name whose second word is a particle. Grapheme-safe extraction matters here for the same reason it does in emoji truncation breaking grapheme clusters.
Migrating a split schema
Most products meet this with two columns already in the database and code that reads them everywhere. The migration is straightforward and worth sequencing, because the intermediate states are all shippable.
Add a full-name column and populate it. For existing rows it is the two parts joined in the order the form collected them, which is right for the readers who filled that form. New rows write the single field directly. Nothing reads the new column yet.
Move the form to one field. Writes now populate the full name; the legacy columns can be filled with a best-effort split or left null for new rows, depending on what still reads them.
Convert the readers one at a time. Greeting templates, invoices, exports, search, sorting. Each conversion is small, and each removes one place where a fragment was assumed to mean something.
Drop the legacy columns when nothing reads them. Verifying that is a code search rather than a guess, and it is worth doing properly: a report or an integration reading a surname column after it stops being written produces empty values in an artifact nobody looks at until a customer does.
The step that needs a decision rather than code is what to do about the greeting. Existing data has a first name that templates have been using, and the single-field migration removes it. Introducing the optional preferred-name field before the migration, and defaulting it from the existing first name, keeps every greeting working while the structural change happens underneath — which turns a visible change in tone into no change at all.
Verification
test.each([
'Sukarno', // mononym
'山田 太郎', // family name first
'María del Carmen García Pérez', // multiple family names and a particle
'Björk Guðmundsdóttir', // patronymic
"Jean-Luc de la Fontaine-O'Brien", // hyphens, particles, apostrophe
])('accepts %s', async (name) => {
await expect(submitForm({ name })).resolves.toMatchObject({ ok: true });
});
test('initials never throw', () => {
expect(initials('Sukarno')).toBe('S');
expect(initials('山田 太郎')).toBe('山');
});
Those five names are worth keeping as a permanent fixture. Each one breaks a different assumption, and a validation change that reintroduces any of them fails immediately.
When to escalate
If a second field is genuinely required by an external system, keep it and label it by that system’s requirement. The failure mode to avoid is a field labelled “Last name” whose real purpose is “the name your card issuer has”.
If names are stored correctly and displayed wrongly, the assumption has moved downstream — into a template concatenating fragments, an email greeting, or a report grouping by a derived surname. Searching for the split rather than the field is what finds those.
If a name cannot be entered because of character restrictions rather than structure, the validation is rejecting scripts or marks it should accept. A name field should permit letters, marks, spaces, hyphens and apostrophes across every script, which is a small Unicode property test rather than a list of allowed characters.
FAQ
What about products that legally require a full legal name?
Ask for the legal name in one field, and separately ask what to call the person. The legal requirement is about the value, not about its structure, and a single field satisfies it for every naming pattern.
Does a single field make deduplication harder?
Slightly, and the split does not make it easy either — two records for the same person differ by punctuation, order and spelling regardless. Deduplication is a matching problem solved with normalization and fuzzy comparison, which works on whole names as readily as on parts.
How should the name be displayed in lists?
As entered. Reordering or abbreviating requires knowing which part is which, which is the assumption being removed. If a display needs to be compact, truncate at a grapheme boundary rather than trying to shorten a specific component.
Is autocomplete="name" well supported?
Yes, and it fills more reliably than the split tokens, because it does not require the browser to have split a stored name the same way your form does. It is one of the practical arguments for the single field, alongside the cultural ones.
Should the field enforce any validation at all?
Very little. Requiring a non-empty value is reasonable; a maximum length in grapheme clusters is reasonable; rejecting control characters is reasonable. Everything beyond that — a minimum length, a required space, a capital letter, a Latin-only character class — rejects real names, and each rule excludes a specific population rather than catching a specific error.
What about profanity or impersonation checks on names?
Those are moderation problems rather than validation problems, and they belong after submission rather than in the field. A blocklist applied at input time rejects legitimate names that happen to contain a substring, which is a well-documented way to exclude people with common surnames in one language because of what they mean in another.
Related
- Internationalizing Forms & Input — the wider rule that country decides structure and locale decides presentation.
- Unicode Text Handling & Collation — sorting names without a derived surname.
- Address form field order by country — the same lesson applied to a field set with genuine structure.
- Emoji truncation breaking grapheme clusters — extracting an initial safely.
Part of Internationalizing Forms & Input.