Skip to content

fix: discussions not submittable - #3676

Merged
isTravis merged 2 commits into
mainfrom
tr/discussionCaptchaFix
Aug 18, 2026
Merged

fix: discussions not submittable#3676
isTravis merged 2 commits into
mainfrom
tr/discussionCaptchaFix

Conversation

@isTravis

Copy link
Copy Markdown
Member

Fix silently dropped discussion submits caused by Altcha's hidden required checkbox

Problem

Typing a comment on a pub draft and clicking Post Discussion does nothing. The console shows:

An invalid form control is not focusable.

Tab-selecting the button and pressing Enter works, which makes it look like a click-vs-keyboard bug. It isn't - it's a timing race with the Altcha widget.

Two facts combine badly:

  1. Altcha renders into the light DOM. The custom element is registered with use_shadow_dom = false (altcha/dist/altcha.js:3091), so the widget puts a real <input type="checkbox"> inside our <form>. That checkbox is required unless auto === 'onsubmit' (altcha.js:2807), and it is only checked once the widget reaches its verified state (altcha.js:2316).
  2. We hide the widget. Altcha.tsx:139 sets display: altchaVisible ? 'block' : 'none', and altchaVisible starts false. Altcha never emits a statechange for the initial unverified state, so the widget is invisible in exactly the state where its checkbox is invalid.

Result: if a submit is attempted before verification completes, the browser hits a required, unchecked control it cannot focus, logs "An invalid form control is not focusable", and cancels the submit. Our onSubmit never runs.

Why verification hadn't completed yet: with auto="onfocus", Altcha begins verifying on the form's first focusin (altcha.js:2292). But DiscussionInput.tsx:62-66 auto-focuses the editor on mount, while Altcha.tsx:34-36 only renders the widget after import('altcha') resolves — so the focus that should have started verification fires before the listener exists. Verification then doesn't start until something else focuses inside the form.

Clicking the button focuses it, which finally fires focusin and starts verification — but that path awaits a 500ms delay plus proof-of-work, while native validation runs synchronously on the same click. So the first click always loses. By the time you tab over and press Enter, that earlier click's verification has finished and the checkbox is checked, so it submits. A freshly loaded form fails the same way on tab+Enter; the keyboard isn't actually privileged.

Altcha would normally surface this — it has an invalid handler that alerts waitAlert (altcha.js:2814, altcha.js:2303) — but DiscussionInput.tsx blanks that string out to suppress the noisy alert, so the failure is completely silent.

Change

Add noValidate to the discussion form in DiscussionInput.tsx.

Both submit handlers already await altchaRef.current?.verify(), so native constraint validation of Altcha's internal checkbox is redundant — and actively harmful, since it gates the submit on state that our own handler is responsible for producing. With it off, the submit event fires, verify() drives the captcha, and the post goes through.

No other validated controls exist in this form: the honeypot input and the guest-name InputGroup are not required.

Testing

  • Post a new inline discussion (highlight text → type → click Post Discussion): posts on the first click, no console error.
  • Post from the pub-bottom input: same.
  • Post a reply (auto="onload", so already verified): unchanged, still instant.
  • biome check clean on the touched file.

@isTravis
isTravis merged commit a335f49 into main Aug 18, 2026
1 check passed
@isTravis
isTravis deleted the tr/discussionCaptchaFix branch August 18, 2026 21:37
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.

1 participant