Skip to the page
TACTILE UI

Kit part · Forms · Inputs · Text areas

Log pad

A writing pad that is still a real textarea. A sheet of ruled paper is set into a machined frame, and the rules move with the words. A small LCD in the foot counts characters or words: it lights amber near the limit and red over it, and the limit is said once, in words, when it is crossed. The pad grows with the text up to a height you choose.

Element
<tui-log-pad>
Needs
kit.css + kit.mjs
Rules
log-pad.rules.md · 6
Finishes
Aluminium · Graphite · Porcelain · Black
Volumes
Tactile · Quiet
On this page
  1. Variants
  2. Every state, at once
  3. API
  4. Markup
  5. Accessibility
  6. How it’s built
  7. Rules
  8. Related parts
01

Variants

280 characters at most

Empty, with its hint
300 characters at most

Near the limit · amber
300 characters at most

Over the limit · red
40 words at most

Counting words
No limit

No limit: it only counts
280 characters at most

Disabled
600 characters at most

Long text scrolls, rules and all
02

Every state, at once

Both finishes, side by side. Hover, pressed and focus are forced with .is-hover, .is-down and .is-focus; checked and disabled are real.

Aluminium

PartEmptyNear the limitOver the limitFocus
Pad
120 characters at most

120 characters at most

120 characters at most

120 characters at most

Graphite

PartEmptyNear the limitOver the limitFocus
Pad
120 characters at most

120 characters at most

120 characters at most

120 characters at most

03

API

NameKindValuesWhat it does
<tui-log-pad>elementmax · unit · warn · rows · max-rowsThe pad. max: the limit, none for no limit. unit: "characters" (default) or "words". warn: how far to the limit the meter goes amber, 0 to 1, 0.9 by default. rows and max-rows: the height it starts at and the most it grows to, in lines.
name · label · placeholder · valueattributeon an empty elementAn empty <tui-log-pad> builds the whole pad from these.
textarea.tui-log-pad__textelementa real textareaThe sheet. Label it, name it, put it in a form. The rules and the margin are its own background.
--lp-lhcustom propertylengthThe line height, and the distance between rules: 28px. Text and rules stay locked together.
.tui-log-pad__foot · __limit · __meterclassprint · lightThe limit in words, and the LCD that counts. The meter is hidden from assistive technology: the textarea’s description carries the limit and the live region carries the crossing.
[data-state]attribute"ok" · "warn" · "over"On the element and on the meter, set by script. Amber glass for warn, red for over.
aria-invalid · setCustomValiditystatewhile overSet on the textarea while the count is past the limit, with a message a form shows. Put maxlength on the textarea if the limit should be hard.
count · textareapropertynumber · elementWhat has been written, in the unit; and the textarea itself.
refresh()methodnoneRecount, recolour and regrow. Call it after setting textarea.value from script.
tui-log-padeventdetail.count · max · unit · stateAfter every change. Bubbles.
logPadCount · logPadState · logPadMeter · logPadSays · logPadLimit · logPadHTMLfunctionkit.mjsThe rules, pure: what has been written, which state that is, what the LCD shows, what to say when the limit is crossed, and the markup for a page that renders one on a server.
04

Markup

<tui-log-pad max="280" unit="characters" rows="4" max-rows="10">
  <label class="tui-label tui-log-pad__label" for="note">Handover note</label>
  <div class="tui-log-pad__pad">
    <textarea class="tui-log-pad__text" id="note" name="note" rows="4"
              aria-describedby="note-limit"></textarea>
    <div class="tui-log-pad__foot">
      <span class="tui-log-pad__limit" id="note-limit">280 characters at most</span>
      <output class="tui-lcd tui-lcd--sm tui-log-pad__meter" data-state="ok"
              data-ghost="888/888" aria-hidden="true">000/280</output>
    </div>
  </div>
  <p class="tui-log-pad__say" role="status"></p>
</tui-log-pad>
import { logPadHTML } from '/kit/kit.mjs';   // also defines <tui-log-pad>

// An empty <tui-log-pad name="note" label="Handover note" max="280"> builds the pad above for itself.
const pad = document.querySelector('tui-log-pad');
pad.textarea;            // the real <textarea>: a form posts it under its own name
pad.count;               // 112, in characters or words as the unit says
pad.refresh();           // after you set textarea.value from script
pad.addEventListener('tui-log-pad', (e) => {
  e.detail.count;        // 112
  e.detail.state;        // 'ok' | 'warn' | 'over'
});

// Over the limit the textarea is aria-invalid and its validity message is set,
// so the form will not submit until the note is back within it.
form.reportValidity();

Needs kit.css and kit.mjs. How to install the kit.

05

Accessibility

  • It is a real <textarea>, named by its label and posted by its form, so nothing about writing, selecting, spelling or autofill is reinvented.
  • The limit is printed in words (“280 characters at most”) and attached to the textarea with aria-describedby, so it is read before anyone types. The LCD repeats the count for the eye and is hidden from assistive technology.
  • Crossing the limit is said once, in a polite live region: “13 characters over. The limit is 280.” Coming back inside it is said once too. Nothing is said in between, so the pad does not talk while someone types.
  • The amber and the red are second signals. Over the limit the textarea is aria-invalid and carries a validity message, so a form will not send it and says why.
  • The digits on the amber and red glass are dark on a light ground: about 8:1 on amber and 5:1 on red.
  • The focus ring goes round the frame, since the sheet is inside it; it uses the finish’s ring colour, which reads on the frame in both finishes.
  • With reduced motion the meter changes colour at once; the pad still grows, since that is a change of size, not an animation.
06

How it’s built

The rules are the textarea’s own background: a repeating gradient exactly one line high, with background-attachment: local, so it is attached to the scrolling text and moves with it, and a margin drawn as a second, fixed layer. The line height is a pixel value shared by the text and the rules, which is what locks the two together; the script reads it to grow the pad in whole lines, from rows up to max-rows, and it scrolls after that. The frame is a raised plate with a 6px rim round a 6px sheet, so its 12px corner is concentric. The paper is the kit’s paper tokens, the same in both finishes. The LCD is the kit’s own, backlit amber and then red by two colour mixes, and its unlit segments are always the same width as the number. The counting, the state and the sentence are pure functions, tested.

07

Rules

log-pad.rules.mdIn the brain

For notes with a length that matters: a handover, a commit message, a status line.

6 rules in this file, with the foundations they rest on and the anti-patterns that break them. Full rules ship in the brain with the Pass.

08

Text area

Longer text in a deeper recess: notes, messages, descriptions. It grows by its corner handle.

Field

Text entry in a recess, the label printed above it, and a hint that says how to fix an error.

02:52min

LCD

A value that changes, on grey-green liquid crystal, with a ghost of the unlit segments behind it: clocks, battery, counters.

Docs
Finish
Volume