Skip to content

feat(frontend): style textarea to match other inputs DEV-2007 - #7285

Open
magicznyleszek wants to merge 9 commits into
mainfrom
leszek/dev-2007-qual-text-ux
Open

feat(frontend): style textarea to match other inputs DEV-2007#7285
magicznyleszek wants to merge 9 commits into
mainfrom
leszek/dev-2007-qual-text-ux

Conversation

@magicznyleszek

@magicznyleszek magicznyleszek commented Jul 20, 2026

Copy link
Copy Markdown
Member

🗒️ Checklist

  1. run linter locally
  2. update developer docs (API, README, inline, etc.), if any
  3. for user-facing doc changes create a Zulip thread at #Support Docs Updates, if any
  4. draft PR with a title <type>(<scope>)<!>: <title> DEV-1234
  5. assign yourself, tag PR: at least Front end and/or Back end or workflow
  6. fill in the template below and delete template comments
  7. review thyself: read the diff and repro the preview as written
  8. open PR & confirm that CI passes & request reviewers, if needed
  9. act on any greptile review below a 5/5 score or leave comment explaining why you won't
  10. delete this checklist section from the final squash commit before merging

📣 Summary

Kobo text inputs now look and behave consistently across TextInput, Textarea, NumberInput, and PasswordInput.

💭 Notes

This branch aligns the shared Kobo styling for the main Mantine input components so their borders, placeholder colors, disabled states, error states, and keyboard focus rings match. It also adds Storybook coverage to make it easy to compare the inputs side by side and catch any visual drift later.

Changes here:

  • InputBase.module.css
    • Centralized the shared input border, disabled, error, and focus styling.
    • Added wrapper-level focus styling so components like PasswordInput show the same focus ring as the others.
  • Textarea.ts and NumberInput.ts
    • Point both components at the shared Kobo input styles instead of separate CSS modules.
  • PasswordInput.ts
    • Added a Kobo theme wrapper for PasswordInput so it uses the same shared input classes.
  • InputBase.stories.tsx
    • Added a comparison story that renders all the themed inputs together.
  • NumberInput.stories.tsx
    • Added a simple NumberInput story for visual checks.

👀 Preview steps

  1. Go to Storybook → Design system → InputBase.
  2. Compare the rendered inputs in the stacked story.
  3. Click into each field and use Tab to move focus between them.
  4. 🔴 Before this change, PasswordInput, TextArea could look different from the other inputs.
  5. 🟢 After this change, the border, focus ring, disabled state, and error styling should match across all of them.

@magicznyleszek
magicznyleszek requested a review from duvld July 20, 2026 20:03
@magicznyleszek magicznyleszek self-assigned this Jul 20, 2026
@magicznyleszek
magicznyleszek marked this pull request as ready for review July 20, 2026 20:03
@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR consolidates the visual styling of Mantine input components (TextInput, Textarea, NumberInput, PasswordInput) by centralising shared CSS rules in InputBase.module.css and pointing all four components at it, replacing the now-deleted NumberInput.module.css and the previous empty Textarea extension.

  • InputBase.module.css gains .control, .visibilityToggle, and wrapper-level focus rules so NumberInput step buttons and PasswordInput's composite wrapper can share the same border, disabled, error, and focus-ring styles.
  • PasswordInput.ts is newly wired to the shared classes and gains an accessible aria-label on the visibility-toggle button.
  • Storybook stories for InputBase (side-by-side comparison) and NumberInput are added, and TextInput is moved from Design system old/ to Design system/.

Confidence Score: 5/5

  • Safe to merge — changes are purely cosmetic CSS/theme consolidation with no logic or data-handling impact.
  • The change deletes a duplicate CSS module, consolidates four input components onto a shared stylesheet, and adds Storybook stories. There are no functional regressions — the only observations are a minor :focus-within vs :focus-visible convention mismatch for PasswordInput on mouse click, and a value vs defaultValue mismatch in a Storybook story that causes a React console warning.
  • No files require special attention.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[InputBase.module.css\nShared styles] --> B[InputBase.ts]
    A --> C[NumberInput.ts\nwas: NumberInput.module.css]
    A --> D[Textarea.ts\nwas: no classNames]
    A --> E[PasswordInput.ts\nnew: uses shared classes]

    B --> F[InputBase component\nborder / disabled / error / focus]
    C --> G[NumberInput component\nborder / disabled / error / focus\ncontrol buttons]
    D --> H[Textarea component\nborder / disabled / error / focus]
    E --> I[PasswordInput component\nborder / disabled / error / focus\nvisibilityToggle styling]

    J[focusRing.css\nGlobal keyboard-only focus] --> F
    J --> G
    J --> H
    J --> I
Loading

Reviews (9): Last reviewed commit: "Merge branch 'main' into leszek/dev-2007..." | Re-trigger Greptile

Comment thread jsapp/js/theme/kobo/Textarea.module.css Outdated
Comment thread jsapp/js/theme/kobo/Textarea.module.css Outdated
Comment thread jsapp/js/theme/kobo/Textarea.module.css Outdated
@magicznyleszek

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

@magicznyleszek

Copy link
Copy Markdown
Member Author

Additionally, mapping innerInput: classes.input in PasswordInput.ts causes two separate focus-ring outlines to render simultaneously — directly undermining the visual consistency goal of the PR.

@greptile-apps testing in the UI, I only see single focus ring

@greptile-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Fair point — if you're only seeing one ring in practice, my concern may have been overstated. That said, the theoretical risk is still there: input (the wrapper) has .input with :focus-within, and innerInput (the <input> element) also has .input with :focus-visible. When the user types, both rules fire simultaneously. If you only see one ring it likely means the outlines are coincidentally overlapping, not that only one is rendered.

Worth a quick sanity check: does the ring look the same when focusing the visibility toggle button vs focusing the text field itself? The toggle button focus would only trigger :focus-within on the wrapper (not :focus-visible on innerInput), so if the rings look identical in both cases, the double-application is genuinely harmless here. If the ring shifts slightly between the two states, that would confirm two separate outlines are in play.

If both cases look correct, happy to drop the concern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants