PostHog / PostHog/posthog

bug(ui): Enter key submits forms while typing in Japanese, Chinese, or Korean (IME composition)

Open
#60,044 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug feature/lemon-ui ui ui-ux-improvement
Dominant language
Python
Stars
39.9k
Forks
3.4k
Avg merge
6h 51m
Merged PRs (30d)
232

Description

When users type using an Input Method Editor (IME), commonly used for Japanese, Chinese, Korean, and several other languages, pressing Enter to confirm a character candidate also submits the surrounding form or action. This makes a number of inputs across the PostHog UI difficult or impossible to use without switching IME off, which is impractical.

For example, typing ue in Japanese IME shows candidates like 上 / 飢え / 植え. Pressing Enter is supposed to confirm the highlighted candidate. Instead, the page also fires its primary action, creating the organization / sending the invite / running the query / saving the title.

A previous fix in PR #51350 addressed this in the LemonInput and LemonTextArea components, but only when consumers use the onPressEnter prop. Many places in the codebase wire Enter via the lower-level onKeyDown prop (or build on top of more primitive components), and those still hit the bug. A one-off follow-up landed for the AI-first home input in PR #60043, but the broader audit needs a single tracking issue.

How to reproduce

  1. Open one of the inputs listed below (the "Create organization" modal is a quick example)
  2. Switch your OS input method to a Japanese, Chinese, or Korean IME (or any IME that uses Enter to confirm)
  3. Type characters that produce candidates (for example, ue in Japanese)
  4. Press Enter to confirm a candidate
  5. Observed: the form submits, the action fires, or the highlighted suggestion is selected
  6. Expected: Enter only confirms the IME candidate. Pressing Enter again on the already-confirmed (non-composing) text should then submit as normal

Where it shows up

This is a single root cause producing many user-visible bugs. Highest impact (form-submitting / action-firing inputs):

  • Creating an organization or project
  • Sending team invites
  • Authorizing an OAuth client
  • Saving a person property
  • Saving a scene, notebook, or workflow step title
  • Saving an inline-edited field (used widely across the UI)
  • Submitting a Lemon dialog form
  • Adding an authorized domain (Conversations)
  • Inserting a link in the support editor (Conversations)
  • Marketing-analytics attribution settings
  • Heatmaps browser URL bar
  • Jump-to-timestamp form
  • Screenshot annotation
  • Tag inputs that add a tag on Enter (LemonInputSelect)

Lower impact (the wrong item gets selected, but no destructive action):

  • Taxonomic filter (combobox, infinite list, autocomplete input)
  • Max slash-command autocomplete
  • Markdown editor inline slash commands

A grep of e.key === 'Enter' across frontend/src/ and products/*/frontend/ after filtering out a11y key === 'Enter' || key === ' ' handlers and intentional modifier shortcuts (metaKey + Enter, ctrlKey + Enter) gives roughly 20 to 25 sites. The exact line numbers as of this writing are catalogued in the additional context section below.

Why it happens

LemonInput and LemonTextArea define their own internal onKeyDown that includes the !e.nativeEvent.isComposing IME guard, but then spread {...props} immediately after, so a consumer-provided onKeyDown overrides the internal one. See https://github.com/PostHog/posthog/blob/master/frontend/src/lib/lemon-ui/LemonInput/LemonInput.tsx#L264-L272.

This makes the guard apply only to consumers that use onPressEnter. Anyone using onKeyDown (which is allowed by the component's prop types) silently loses the guard. The same shape exists in LemonTextArea. Components built directly on TextareaPrimitive, Autocomplete.Input, or native inputs never had the guard at all.

Suggested approaches

Not mutually exclusive:

  1. Per-site fix: add && !e.nativeEvent.isComposing to each Enter check across the codebase. Mechanical, easy to review, can ship incrementally.
  2. Library-level fix: change LemonInput and LemonTextArea to wrap (not replace) the consumer's onKeyDown so the IME guard always applies. Needs care because the components also handle stopPropagation and onPressEnter, and the consumer's handler should still receive non-Enter keys.

Additional context

Specific file references (line numbers may drift):

File Line What Enter does
frontend/src/scenes/organization/CreateOrganizationModal.tsx 77 Creates org
frontend/src/scenes/project/CreateProjectModal.tsx 119 Creates project
frontend/src/scenes/settings/organization/InviteModal.tsx 231, 249 Sends team invites
frontend/src/scenes/oauth/OAuthAuthorize.tsx 98 Confirms OAuth name
frontend/src/scenes/persons/NewProperty.tsx 121 Saves person property
frontend/src/scenes/web-analytics/tabs/marketing-analytics/frontend/components/settings/AttributionSettings.tsx 126 Submits attribution setting
frontend/src/scenes/heatmaps/components/HeatmapsBrowser.tsx 130 Navigates to URL
frontend/src/layout/scenes/components/SceneTitleSection.tsx 512 Saves scene title
frontend/src/scenes/notebooks/Nodes/components/NotebookNodeTitle.tsx 116 Saves notebook node title
frontend/src/scenes/notebooks/Nodes/NotebookNodeLatex.tsx 76 Confirms LaTeX
frontend/src/scenes/surveys/hosted-canvas/InlineEditable.tsx 85 Saves inline-edited field
frontend/src/lib/components/EditableField/EditableField.tsx 167 Saves editable field
frontend/src/lib/lemon-ui/LemonDialog/LemonDialog.tsx 213, 219 Submits dialog form
frontend/src/lib/lemon-ui/LemonInputSelect/LemonInputSelect.tsx 549 Adds typed tag/selection
frontend/src/lib/components/SearchAutocomplete/SearchAutocomplete.tsx 215 Confirms autocomplete selection
frontend/src/lib/components/DateFilter/JumpToTimestampForm.tsx 50 Jumps to typed timestamp
frontend/src/lib/components/TakeScreenshot/ScreenShotEditor.tsx 503 Screenshot text input
frontend/src/scenes/product-tours/components/NewProductTourModal.tsx 111 Saves new product tour
products/conversations/frontend/scenes/settings/AuthorizedDomains.tsx 43 Adds authorized domain
products/conversations/frontend/components/Editor/SupportEditor.tsx 532 Inserts link
products/workflows/frontend/Workflows/hogflows/steps/components/StepView.tsx 127, 173 Saves workflow step name

Combobox-style inputs (lower impact):

  • frontend/src/lib/components/TaxonomicFilter/menu/Combobox.tsx:377
  • frontend/src/lib/components/TaxonomicFilter/InfiniteList.tsx:485
  • frontend/src/lib/components/TaxonomicFilter/headless/AutocompleteInput.tsx:990
  • frontend/src/scenes/max/components/SlashCommandAutocomplete.tsx:64
  • frontend/src/lib/components/MarkdownEditor/inline/inlineMarkdownSlashCommands.tsx:360

Related work:

  • Original fix: PR #51350
  • AI-first home input follow-up: PR #60043

Debug info

  • PostHog Cloud, Debug information: [please copy/paste from https://us.posthog.com/settings/project-details#variables or https://eu.posthog.com/settings/project-details#variables]
  • PostHog Hobby self-hosted with docker compose, version/commit: [please provide]
  • PostHog self-hosted with Kubernetes (deprecated, see Sunsetting Kubernetes support), version/commit: [please provide]

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with frontend/src/lib/lemon-ui/LemonInput/LemonInput.tsx and LemonTextArea, then review the Enter handlers listed in the issue across frontend/src and products/*/frontend/. Compare the existing PR #51350 behavior and reproduce with a Japanese, Chinese, or Korean IME. Done means composing Enter confirms the candidate without firing an action, while a later non-composing Enter retains normal behavior across the affected inputs.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
accessibility, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.