Skip to content

fix(ui): block Enter on a form with several options - #426

Open
0065paula wants to merge 4 commits into
mainfrom
feat/complex-form-enter-submit
Open

0065paula wants to merge 4 commits into
mainfrom
feat/complex-form-enter-submit

Conversation

@0065paula

Copy link
Copy Markdown
Contributor

What

Enter inside a field no longer submits a form with two or more setting options; submission comes from the submit button (Tab to it and press Enter, or click it). Single-field forms and widgets that own Enter (comboboxes, array entry editors, textareas) keep their behaviour.

Two prerequisites surfaced while doing this:

  • keyboard focus was invisible on every button — Tailwind reads shadow-[var(…)] as a shadow colour, so the focus ring and the push-button/card/menu shadows were never rendered (29 places);
  • nothing prevented the same mistake from coming back.

Changes

  • foundation/lib/enter-submit.ts + foundation/hooks/use-form-enter-submit-guard.ts, wired into ResourceForm, CreateApiKeyForm, ApiKeyLimitsCard and FunctionDialog. Complexity is counted from the data-form-option markers FormFieldGroup renders, so a single-field form (Workspace) keeps native Enter-to-submit. A composing Enter is left to the input method and only its follow-up submit is refused.
  • Focus-visible now follows the design system's button and checkbox spec: 2px outline, 2px offset, stroke-outstanding-base (stroke-serious-base for Danger) on button-like controls; form fields keep the effect-outline-active-focus halo. All 29 ambiguous shadow utilities were switched to [box-shadow:var(…)], or shadow-[shadow:var(…)] where the shadow composes with ring-*.
  • tools/check-shadow-utilities.cjs rejects the ambiguous syntax; it runs in the pre-commit hook and from yarn lint:ci, which CI already executes.

Verification

  • yarn typecheck, yarn dep-check, yarn knip, biome, both i18n gates and the new shadow check pass.
  • New unit tests: field Enter blocked in a two-option form, kept in a single-option form, Enter on the submit button untouched, a widget that already claimed Enter (defaultPrevented), and a composing Enter whose follow-up submit is refused. The only local failures are the pre-existing Timestamp.render.test.tsx timezone cases (they also fail on main outside UTC).
  • Browser QA on the mock preview: field Enter does not submit; Tab to Save + Enter submits; ArrowDown + Enter still selects in a combobox; CTA/Ordinary focus shows outline: 2px solid rgb(0,128,255) with outline-offset: 2px and the button shadow restored; input halo unchanged.

Notes

  • Deliberately out of scope: auth pages (Enter-to-submit is expected there) and playground chat inputs (Enter sends).

@0065paula
0065paula force-pushed the feat/complex-form-enter-submit branch from b9264f2 to 079894a Compare September 18, 2026 08:14
@codecov-commenter

codecov-commenter commented Sep 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Enter from a field of a form with two or more setting options no longer
submits it: submission has to come from the submit button (Tab to it and
press Enter, or click it). Single-field forms and widgets that own Enter
(comboboxes, array entry editors, textareas) keep their behavior.
Tailwind resolves a bare `shadow-[var(--token)]` as a shadow *colour*, so
every button focus ring and the push-button/card/menu elevation shadows were
silently dropped, leaving keyboard focus invisible (focus-visible:outline-none
left a transparent outline) — the Card hit this earlier and documented it.

- Use the unambiguous property form (`[box-shadow:var(--token)]`, or
  `shadow-[shadow:var(--token)]` where a ring composes with the shadow)
  for all 29 occurrences.
- Buttons, tabs, checkbox, segmented control and auth buttons now follow the
  design system's button/checkbox spec for focus-visible: 2px outline, 2px
  offset, stroke-outstanding-base (stroke-serious-base for Danger).
`shadow-[var(--token)]` is read by Tailwind as a shadow *colour*, so the
element renders no box-shadow at all — which is how the button focus ring
silently disappeared. Card documented the trap in a comment; 29 other places
still hit it, so guard it mechanically:

- tools/check-shadow-utilities.cjs scans src/ (comment lines excluded) and
  points at [box-shadow:var(--token)] / shadow-[shadow:var(--token)]
- runs in the pre-commit hook, and in CI through `yarn lint:ci`
- noted in contributing/architecture.md conventions
@0065paula
0065paula force-pushed the feat/complex-form-enter-submit branch from 079894a to 6cb8457 Compare September 18, 2026 08:31
Codecov flagged the new lines in the form hosts, the drawer chip and the guard
itself as uncovered. Cover them where the behaviour lives:

- the guard treats a select as a field control and ignores non-element targets
- the API key dialog and the playground function dialog submit from the button
  and refuse Enter inside a field
- the trace drawer renders its formatted/raw switch for a formattable body
@0065paula 0065paula changed the title Feat/complex form enter submit fix(ui): block Enter on a form with several options Sep 18, 2026
@Yuyz0112

Copy link
Copy Markdown
Contributor

Thanks for the review. Please address the following points:

  1. package.json:104: Could this hook configuration follow the same pattern as the other commit hooks, rather than being added to lint? Please clarify the intended convention and keep the configuration consistent.

  2. src/domains/api-key/components/ApiKeyLimitsCard.tsx:167 and src/domains/endpoint/components/FunctionDialog.tsx:194: The form-related handling appears to be implemented in several scattered places, which may allow similar issues to recur. Could we consider extracting a shared abstraction for this behavior, or explain why a shared abstraction would not fit here?

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.

4 participants