Skip to content
Site volume
Colourway

Components

Character count

"120 of 2,000" under a field; it speaks only near the limit.

  • Experimental
  • Reading layer
  • Client leaf
  • Since 0.9.0
  • Press check
Import from@maxgrits/overprint-react/character-count
On this page

CharacterCount sits under a Textarea or an Input and prints how much of the limit is used ("120 of 2,000") in meta. It follows the field named by htmlFor, so the field stays a server component. Inside the last 10 % the figure turns to the ink at weight 600 and says how many characters are left.

Example#

Look of this example

0 of 280

Live render of examples/character-count/basic.tsx

Usage#

Use a character count under any field with a hard limit, so writers see the budget before they run out. It suits messages, bios and short answers; a field with no limit needs no count.

  • Placement. Directly under its field, in the meta role, linked with aria-describedby so the count is read with the field.
  • The last tenth. Inside the last 10 % of maxLength the figure turns to the text ink at weight 600 and a polite live region says how many characters are left. Before that it stays silent.
  • Server-safe fields. It follows the field named by htmlFor, so the Textarea or Input stays a server component.

Anatomy#

0 of 280

The parts of examples/character-count/basic.tsx, numbered:
  1. FigureUsed of the limit, in the meta role; near the end, what is left.data-mk-part="figure"

Volume#

Reading layer: identical at every volume.

  • Quiet

    0 of 280

    Docs, forms, legal and long reads. Flat inks, no art in motion.

  • Studio

    0 of 280

    The site default. Art on its own plates, one display moment per view.

  • Press

    0 of 280

    Hero moments, covers and campaigns. Halftone fields and the second ink.

  • Rave

    0 of 280

    Launches, posters and the 404. Every ink, and the words still win.

Content#

  • The figure reads "120 of 2,000", with the thousands separator.
  • Near the limit it says what is left: "18 characters left". It never scolds.
  • Set limits that fit the answer you want; a 280-character "Tell us about your project" asks for a tweet.

Do and don't#

Do

0 of 280

A count tied to its field, read with it.

Don't

0/280

Bare digits, with no field and no words.

A count is part of the field's description. Unlinked digits under a box are noise to a screen reader and cryptic to everyone else.

Accessibility#

  • The figure is not live, so typing is never interrupted; a polite live region speaks only inside the last 10 % ("200 characters left").
  • Give it an id and add that id to the field's aria-describedby.
  • The field's own maxLength stops the typing; the count only reports it.

The colour pairs it prints, with their contrast on both papers:

TextSurfaceRoleBoneNight
--mk-text-2--mk-surfaceuinot in this looknot in this look
--mk-text--mk-surfaceuinot in this looknot in this look

Process at Studio, normal contrast. Every look: the press check.

Props#

PropTypeDefaultDescription
htmlFor requiredstringnoneThe id of the field it counts.
maxLength requirednumbernone
defaultLengthnumber0The count before the field reports (server render; default 0).
copyPartial<CharacterCountCopy>none

Plus 279 React and DOM attributes passed through to the root element (className, ref, aria-*, event handlers and the rest). Generated from CharacterCountProps in packages/overprint-react/src/reading/character-count/character-count.tsx.

Tokens#

System tokens (8)

Scanned from its CSS at build and checked against its registry entry; 2 read but not declared there.

Changelog#

Arrived in 0.9.0.

0.9.024 October 2026