Skip to content

feat: subdue read-only field border and drop hover#1060

Draft
lmjabreu wants to merge 2 commits into
feat/readonly-variant-fieldsfrom
feat/readonly-field-subdued-border
Draft

feat: subdue read-only field border and drop hover#1060
lmjabreu wants to merge 2 commits into
feat/readonly-variant-fieldsfrom
feat/readonly-field-subdued-border

Conversation

@lmjabreu

@lmjabreu lmjabreu commented Jun 6, 2026

Copy link
Copy Markdown

No linked issue. Follow-up to #1059, stacked on feat/readonly-variant-fields (base of this PR). Review #1059 first; this targets that branch and will retarget main once #1059 merges.

Short description

Read-only TextField and TextArea reused the editable idle border and still brightened it on hover and focus. On a field you cannot edit, that hover/focus reaction reads as interactive. This refines the read-only treatment:

  • Subdued border. Read-only fields use --reactist-divider-tertiary (one step lighter than the editable idle border) so a locked field is visually quieter.
  • No hover reaction. The hover border-brightening is gated out for read-only fields.
  • Focus is kept. Read-only fields remain keyboard-focusable (you can tab in to read and copy), so removing the focus indicator would break WCAG 2.4.7 Focus Visible. The focus border stays.

This applies to the read-only state regardless of readOnlyVariant; the variant only toggles the grey fill. It covers the default and the bordered variant of both components.

Implementation notes

  • The read-only fill class is split out as readOnlyFilled, so the read-only state (subdued border, no hover) and the fill (grey background) are independent. plain read-only fields get the subdued border without the fill.
  • BaseField gains a readOnly prop. The bordered border is drawn by BaseField, so it needs the read-only signal to gate hover and apply the subdued color. The prop is optional and additive.
  • Error tone still wins: the alert border uses !important, so a read-only field in an error state keeps its red border.

Scope

This is intentionally separate from #1059. #1059 is purely additive (a new prop, no change to existing appearance). This PR changes the default read-only appearance of every field across the app, so it carries the visual diffs and is reviewed on its own.

PR Checklist

  • Added tests for bugs / new features
  • Updated docs (storybooks, readme)
  • Reviewed and approved Chromatic visual regression tests in CI

Read-only TextField and TextArea reused the editable idle border and
still brightened on hover and focus, which read as interactive on a
field that is not. Read-only fields now use a subdued border
(--reactist-divider-tertiary) and no longer react to hover. The focus
border is kept, since read-only fields stay keyboard-focusable for
reading and copying (WCAG 2.4.7).

Applies to the read-only state regardless of readOnlyVariant (the
variant only toggles the grey fill) and covers the default and bordered
variants of both components. BaseField gains a readOnly prop so the
bordered border, which it owns, can be gated. The fill class is split
out as readOnlyFilled so the state and the fill are independent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lmjabreu

lmjabreu commented Jun 6, 2026

Copy link
Copy Markdown
Author

@doistbot /review

@doistbot doistbot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for refining the read-only visual behaviors and cleanly separating the state from the fill variant, Luis 🤗.

Few things worth tightening:

  • Expand the tests for both TextField and TextArea to include a variant="bordered" case, ensuring the outer containers correctly receive the readOnly class rather than only checking the inner input elements.

I also included a few optional follow-up notes in the details below.

Optional follow-up notes (2)
  • [P3] src/text-area/text-area.tsx:112: Since BaseField receives readOnly on line 107 and natively handles the subdued border and hover gating for the .bordered wrapper (via base-field.module.css), passing styles.readOnly here is redundant. You can remove this line, and simplify text-area.module.css (lines 54-60) to only target the :not(.bordered) variant, exactly like text-field does: css .textAreaContainer:not(.bordered) textarea.readOnly { border-color: var(--reactist-divider-tertiary); } .textAreaContainer:not(.bordered) textarea:not(.readOnly):hover { border-color: var(--reactist-inputs-hover); }
  • [P3] src/text-field/text-field.mdx:94: This new note now conflicts with the sentence just above it that says readOnlyVariant="plain" makes the field look identical to its editable state. After this change, plain read-only fields still get the subdued border/no-hover treatment, so please update that earlier sentence here (and the matching copy in text-area.mdx) to keep the docs consistent.

Share FeedbackReview Logs

Comment thread src/text-field/text-field.test.tsx
Comment thread src/text-area/text-area.test.tsx
…Area

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants