Skip to content

feat: add readOnlyVariant to TextField and TextArea#1059

Open
lmjabreu wants to merge 2 commits into
mainfrom
feat/readonly-variant-fields
Open

feat: add readOnlyVariant to TextField and TextArea#1059
lmjabreu wants to merge 2 commits into
mainfrom
feat/readonly-variant-fields

Conversation

@lmjabreu

@lmjabreu lmjabreu commented Jun 6, 2026

Copy link
Copy Markdown

No linked issue. Component-library follow-up from building read-only description views in todoist-web.

Short description

TextField and TextArea hardcode a grey fill on their read-only state, with no way to opt out. Consumers that want a read-only field to read as plain text override the fill with their own CSS.

This adds a readOnlyVariant prop to both (also inherited by PasswordField):

  • filled (default) keeps today's grey fill, so existing usage is unchanged.
  • plain suppresses the fill, so a read-only field matches its editable appearance.

The prop only applies when readOnly is set. TextArea's CSS moves from the textarea[readonly] selector to a .readOnly class so the fill can be gated on the variant; the default render is identical to before. The shared types live in base-field.

This is the first of three styling-only PRs for the read-only state (#1060 subdues the border and drops hover; #1061 fixes the bordered fill). None of them removes part of the component.

On the two variants

Review asked whether we need two (discussion). Long term, no: the goal is one read-only style for genuine inputs (a copyable token, a feed URL), with the no-fill case moving to a separate EditableText component for inline-editable display text.

plain stays for now because two todoist-web surfaces still render that way (goal-edit-view, project-details-sidebar). Both are being removed but exist in code today, so dropping the variant now would regress them. The prop replaces their CSS overrides in the meantime. Removing plain is a separate PR once those surfaces are gone.

PR Checklist

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

TextField and TextArea hardcoded a grey read-only fill with no opt-out.
Add a readOnlyVariant prop ('filled' | 'plain', default 'filled') so
consumers can render a read-only field without the fill. PasswordField
inherits it via TextField. The default preserves existing behaviour.

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 Luis for cleanly implementing the new readOnlyVariant prop to give us more visual flexibility with read-only fields 😎 👊.

Few things worth tightening:

  • Ensure the new tests for both TextField and TextArea verify that the components remain functionally non-editable when readOnlyVariant="plain" is passed, rather than just asserting on the styling classes.

Share FeedbackReview Logs

Comment thread src/text-field/text-field.test.tsx Outdated
Comment thread src/text-area/text-area.test.tsx Outdated
Address Doistbot review on #1059: the plain-variant cases only checked
the styling class. Also assert typing does not change the value so a
regression dropping readOnly on the plain path can't pass.

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

@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.

Thank you Luis for the clean, well-tested addition of the readOnlyVariant to our text components 🤗.

No issues were flagged during the review.

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

Optional follow-up note (1)
  • [P3] src/text-area/text-area.module.css:32: For TextArea, switching the default filled style from textarea[readonly] to a .readOnly class duplicates the same state in JS and CSS. The filled case can stay anchored to the native readonly attribute, and readOnlyVariant="plain" can add a small opt-out class/attribute instead. That keeps the visual default tied to the semantic readonly state and removes one sync point to maintain.

Share FeedbackReview Logs

@lmjabreu lmjabreu requested review from a team, doist-frontend and engfragui and removed request for a team and doist-frontend June 7, 2026 08:18
@lmjabreu

lmjabreu commented Jun 7, 2026

Copy link
Copy Markdown
Author

@engfragui tagging you on this one for review – can't recall which user/group you recommended on the last meeting 😅 Feel free to re-assign.

@henningmu

Copy link
Copy Markdown
Contributor

@lmjabreu see the linked handbook docs in the template: https://handbook.doist.com/doc/code-reviews-THNOSl1QID#h-15-assign-a-random-reviewer (it's @doist/frontend-product 🙌)

@lmjabreu lmjabreu requested review from a team and craigcarlyle and removed request for a team and engfragui June 8, 2026 08:40
@gnapse

gnapse commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

I'm still not sure if I understand why we need two variants for read-only mode. Why wouldn't we want consistency instead? That is, that read-only input fields always show consistently in the same way no matter what.

I think we should not have the gray background variant at all, even if it's the default today. Graying out the field is more appropriate for disabled fields. What do you think?

@lmjabreu lmjabreu requested a review from a team June 8, 2026 15:15
@pawelgrimm

pawelgrimm commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Are we talking about these components?
CleanShot 2026-06-08 at 13 50 42@2x

They doesn't read like a variant of TextField and TextArea to me — they're more like a Text that turns into an edit form when you click on it. Perhaps the right solution is to develop a new component for that behavior and call it something like EditableText or InlineEditableText or something along those lines?

@engfragui engfragui removed the request for review from a team June 9, 2026 12:56
@lmjabreu

Copy link
Copy Markdown
Author

why we need two variants for read-only mode

We don't! :D The plain variant only existed because of Goals and the old Project Descriptions sidebars (both being dropped, but they still exist in code today).

The use-case for the plain variant is better served by a separate component (EditableText like Paweł says).

FWIW, EditableText has a lot of use-cases across TD: project name, section name/description, task name/description, and so on. Basically any text that can be edited inline, but it's usually styled as display text (so.. contenteditable 😅)

Regarding the grey 'disabled' styling: agree, that's addressed in subsequent PRs.

TLDR: one read-only style for inputs, and one editable-text component for editable (display/UI) text.

@lmjabreu lmjabreu requested review from Bloomca and removed request for craigcarlyle June 11, 2026 21:52
@gnapse

gnapse commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

@lmjabreu if I read your comment correctly, then we can close this PR without merging, right?

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.

5 participants