# Text

> Keeping text as it is typed, counting it as people count, and bringing every way of typing a character into one form before a value is read.

Text is the value people type most, and the one an interface is most tempted to
correct. An interface that handles it well keeps what was typed, counts it as
people count, and checks it only when the person has finished — and, beneath
every field that reads a number or a date, brings the many ways a character can
be typed into one form before reading it.

## Best practices

**Keep text as it was typed.** Do not trim it, change its case, or replace its
characters. What someone typed is what they meant; the space at the end of a
line of poetry is theirs.

**Drop space at the ends only where it is never meant.** An email address, an
identifier or a code is not changed by the space around it, and space is often
pasted with it. There, space at either end is dropped when the text is
committed, and text that is only space is no text at all.

**Count characters as people see them.** A limit of twenty characters is twenty
of what a reader would count, in any script: an emoji made of several code
points is one, a flag is one, a letter with its accent is one, whether the
accent was typed as part of it or after it.

**Check when the text is finished, never while it is typed.** A limit that stops
the keyboard cuts a word in half, breaks an input method's composition — which
passes through longer text on its way to shorter — and silently drops the end of
what was pasted. Text past a limit is kept, and marked, and the reason said,
when it is committed.

**Match a pattern against the whole text.** A pattern describes what the text
is, not something it contains: a code of letters does not accept letters
followed by a digit. Patterns are read as Unicode, so "a letter" is a letter of
any script. A pattern that is not a valid expression constrains nothing; it is
a fault of the field, and is not the person's to suffer.

**Show text as it is held.** What was typed is shown back unchanged.

**No text is no value.** An empty field holds nothing, which a field that
requires a value says; it does not hold an empty string the person never chose.

## What is typed, made plain

People type the same thing in many ways, and a field that reads a number or a
date should accept them all without each field handling each. Before a value is
read from text:

- characters an input method types in full width (`１２３`, `／`, `－`) are the
  ordinary characters;
- digits of every numbering system a locale may use — Arabic-Indic, Devanagari,
  Bengali, Thai and others — are the digits 0 to 9;
- every minus sign, and every dash that looks like one, is a minus;
- the invisible marks some locales set around signs and separators, to keep
  them in order in right-to-left text, are let go.

A number is read from a stricter form, which never lets something that only
looks like a digit become one:

- a superscript, a fraction or an enclosed numeral is not a digit: `5²` is not
  52, and `½` is not 12;
- a minus is a minus, but a dash between two numbers is a dash, so `10–20`
  stays a range, which is no number;
- primes, and the curly quotes a keyboard substitutes for them, are feet and
  inches: `5′10″` and `5’10”` are `5'10"`;
- what a Japanese keyboard types for a minus, a decimal point and a comma —
  `ー`, `。`, `、` — is read as such where it touches a digit, and is left as it
  is elsewhere;
- every kind of space is a space.

Text that is already plain ASCII, which is most of what is typed, is left
exactly as it is.

## Platform considerations

**Input methods.** A field must leave text alone while an input method is
composing: nothing is checked, counted or rewritten until the composition is
committed.

**Assistive technology.** A field whose text breaks a limit or a pattern is
marked invalid, with the reason as its description.

See also [Text field](https://ui.publictheta.com/components/text-field.md), [Numbers](https://ui.publictheta.com/foundations/number-type.md)
and [Dates](https://ui.publictheta.com/foundations/date-type.md).

## Behaviour

Each statement is verified by a test in Chromium, Chromium (touch), Firefox, WebKit, WebKit (touch), unless it names the environments it applies to or is marked open.

### Reading

- Text is kept exactly as typed: nothing is trimmed, folded or rewritten.
- No text is no value.
- Where space at the ends is never meant, it is dropped, and space alone is no text.
- Is shown as it is held.

### Length

- Is counted in characters as people see them: a family, a flag and an accented letter are one each.
- Text shorter than the least or longer than the most is refused, and says which.

### Patterns

- A pattern is matched by the whole text, not by a part of it.
- A pattern is read as Unicode: a letter is a letter of any script.
- A pattern that is not a regular expression constrains nothing, rather than failing.

### What is typed, made plain

- What an input method types in full width is read as the ordinary characters.
- Digits of any numbering system are read as the digits 0 to 9.
- Every minus sign, and every dash that looks like one, is a minus.
- The marks some locales set around signs and separators are let go.
- Plain ASCII is already plain, and is left exactly as it is.

### What is typed, as a number is read from it

- A superscript, a fraction or an enclosed numeral is not a digit: 5² is not 52.
- A minus sign is a minus; a dash is a dash, which is a minus only before a number.
- Primes, and the quotes a keyboard puts in their place, are feet and inches.
- What a Japanese keyboard types for a minus, a point and a comma is read as such beside a digit.
- The Arabic percent sign is a percent sign, and the spaces of every kind a space.
- A digit no numbering system names is not taken for one.

## Reference implementation

React: `npx shadcn@latest add https://ui.publictheta.com/r/text-type.json`
