diff --git a/README.md b/README.md index a0194613c..adfabf68e 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ _View an example:_ [the `navigation-drawer` guide](https://github.com/GoogleChro #### The full list
-103 modern web features +104 modern web features ### CSS & Layout (51 features) @@ -123,26 +123,26 @@ _View an example:_ [the `navigation-drawer` guide](https://github.com/GoogleChro | [<link rel="preload">](https://web-platform-dx.github.io/web-features-explorer/features/link-rel-preload/) | [inert](https://web-platform-dx.github.io/web-features-explorer/features/inert/) | [popover="hint"](https://web-platform-dx.github.io/web-features-explorer/features/popover-hint/) | | [blocking="render"](https://web-platform-dx.github.io/web-features-explorer/features/blocking-render/) | [Interest invokers](https://web-platform-dx.github.io/web-features-explorer/features/interest-invokers/) | | -### JavaScript & APIs (32 features) +### JavaScript & APIs (33 features) | | | | | :--- | :--- | :--- | -| [AbortController and AbortSignal](https://web-platform-dx.github.io/web-features-explorer/features/aborting/) | [Language detector](https://web-platform-dx.github.io/web-features-explorer/features/languagedetector/) | [Scheduler API](https://web-platform-dx.github.io/web-features-explorer/features/scheduler/) | -| [document.modelContext](https://web-platform-dx.github.io/web-features-explorer/features/document-modelcontext/) | [LanguageModel](https://web-platform-dx.github.io/web-features-explorer/features/languagemodel/) | [Speculation rules](https://web-platform-dx.github.io/web-features-explorer/features/speculation-rules/) | -| [enterkeyhint](https://web-platform-dx.github.io/web-features-explorer/features/enterkeyhint/) | [Lazy-loading images and iframes](https://web-platform-dx.github.io/web-features-explorer/features/loading-lazy/) | [Summarizer](https://web-platform-dx.github.io/web-features-explorer/features/summarizer/) | -| [Event timing](https://web-platform-dx.github.io/web-features-explorer/features/event-timing/) | [Long animation frames](https://web-platform-dx.github.io/web-features-explorer/features/long-animation-frames/) | [SVG](https://web-platform-dx.github.io/web-features-explorer/features/svg/) | -| [Federated credential management](https://web-platform-dx.github.io/web-features-explorer/features/fedcm/) | [Navigation API](https://web-platform-dx.github.io/web-features-explorer/features/navigation/) | [Temporal](https://web-platform-dx.github.io/web-features-explorer/features/temporal/) | -| [Fetch](https://web-platform-dx.github.io/web-features-explorer/features/fetch/) | [Page visibility](https://web-platform-dx.github.io/web-features-explorer/features/page-visibility/) | [Top-level await](https://web-platform-dx.github.io/web-features-explorer/features/top-level-await/) | -| [fetchLater](https://web-platform-dx.github.io/web-features-explorer/features/fetchlater/) | [Page visibility state](https://web-platform-dx.github.io/web-features-explorer/features/page-visibility-state/) | [Translator](https://web-platform-dx.github.io/web-features-explorer/features/translator/) | -| [Form-associated WebMCP attributes](https://web-platform-dx.github.io/web-features-explorer/features/declarative-webmcp/) | [Partitioned cookies](https://web-platform-dx.github.io/web-features-explorer/features/partitioned-cookies/) | [User agent client hints](https://web-platform-dx.github.io/web-features-explorer/features/ua-client-hints/) | -| [inputmode](https://web-platform-dx.github.io/web-features-explorer/features/inputmode/) | [Permissions policy](https://web-platform-dx.github.io/web-features-explorer/features/permissions-policy/) | [Web authentication](https://web-platform-dx.github.io/web-features-explorer/features/webauthn/) | -| [Intersection observer](https://web-platform-dx.github.io/web-features-explorer/features/intersection-observer/) | [Registered custom properties](https://web-platform-dx.github.io/web-features-explorer/features/registered-custom-properties/) | [Web authentication signal methods](https://web-platform-dx.github.io/web-features-explorer/features/webauthn-signals/) | -| [Intl.DurationFormat](https://web-platform-dx.github.io/web-features-explorer/features/intl-duration-format/) | [Resize observer](https://web-platform-dx.github.io/web-features-explorer/features/resize-observer/) | | +| [AbortController and AbortSignal](https://web-platform-dx.github.io/web-features-explorer/features/aborting/) | [Keyboard events](https://web-platform-dx.github.io/web-features-explorer/features/keyboard-events/) | [Resize observer](https://web-platform-dx.github.io/web-features-explorer/features/resize-observer/) | +| [document.modelContext](https://web-platform-dx.github.io/web-features-explorer/features/document-modelcontext/) | [Language detector](https://web-platform-dx.github.io/web-features-explorer/features/languagedetector/) | [Scheduler API](https://web-platform-dx.github.io/web-features-explorer/features/scheduler/) | +| [enterkeyhint](https://web-platform-dx.github.io/web-features-explorer/features/enterkeyhint/) | [LanguageModel](https://web-platform-dx.github.io/web-features-explorer/features/languagemodel/) | [Speculation rules](https://web-platform-dx.github.io/web-features-explorer/features/speculation-rules/) | +| [Event timing](https://web-platform-dx.github.io/web-features-explorer/features/event-timing/) | [Lazy-loading images and iframes](https://web-platform-dx.github.io/web-features-explorer/features/loading-lazy/) | [Summarizer](https://web-platform-dx.github.io/web-features-explorer/features/summarizer/) | +| [Federated credential management](https://web-platform-dx.github.io/web-features-explorer/features/fedcm/) | [Long animation frames](https://web-platform-dx.github.io/web-features-explorer/features/long-animation-frames/) | [SVG](https://web-platform-dx.github.io/web-features-explorer/features/svg/) | +| [Fetch](https://web-platform-dx.github.io/web-features-explorer/features/fetch/) | [Navigation API](https://web-platform-dx.github.io/web-features-explorer/features/navigation/) | [Temporal](https://web-platform-dx.github.io/web-features-explorer/features/temporal/) | +| [fetchLater](https://web-platform-dx.github.io/web-features-explorer/features/fetchlater/) | [Page visibility](https://web-platform-dx.github.io/web-features-explorer/features/page-visibility/) | [Top-level await](https://web-platform-dx.github.io/web-features-explorer/features/top-level-await/) | +| [Form-associated WebMCP attributes](https://web-platform-dx.github.io/web-features-explorer/features/declarative-webmcp/) | [Page visibility state](https://web-platform-dx.github.io/web-features-explorer/features/page-visibility-state/) | [Translator](https://web-platform-dx.github.io/web-features-explorer/features/translator/) | +| [inputmode](https://web-platform-dx.github.io/web-features-explorer/features/inputmode/) | [Partitioned cookies](https://web-platform-dx.github.io/web-features-explorer/features/partitioned-cookies/) | [User agent client hints](https://web-platform-dx.github.io/web-features-explorer/features/ua-client-hints/) | +| [Intersection observer](https://web-platform-dx.github.io/web-features-explorer/features/intersection-observer/) | [Permissions policy](https://web-platform-dx.github.io/web-features-explorer/features/permissions-policy/) | [Web authentication](https://web-platform-dx.github.io/web-features-explorer/features/webauthn/) | +| [Intl.DurationFormat](https://web-platform-dx.github.io/web-features-explorer/features/intl-duration-format/) | [Registered custom properties](https://web-platform-dx.github.io/web-features-explorer/features/registered-custom-properties/) | [Web authentication signal methods](https://web-platform-dx.github.io/web-features-explorer/features/webauthn-signals/) |
-131 real-world developer use cases +132 real-world developer use cases

accessibility

@@ -183,6 +183,7 @@ _View an example:_ [the `navigation-drawer` guide](https://github.com/GoogleChro - **[branded-select-styling](https://github.com/GoogleChrome/modern-web-guidance/blob/main/skills/modern-web-guidance/guides/forms/branded-select-styling.md)**: Create custom select elements whose button, picker, arrow icon, and checkmark all seamlessly match your brand or design system's typography, colors, spacing, and border treatments. - **[custom-select-picker-layouts](https://github.com/GoogleChrome/modern-web-guidance/blob/main/skills/modern-web-guidance/guides/forms/custom-select-picker-layouts.md)**: Create custom select pickers whose options are positioned in unique or interesting ways, rather than the traditional stacked list of options. - **[form-fields-automatically-fit-contents](https://github.com/GoogleChrome/modern-web-guidance/blob/main/skills/modern-web-guidance/guides/forms/form-fields-automatically-fit-contents.md)**: Allow form fields to grow and shrink to fit the user input, e.g. as the user types or selects a different option. Apply maximum and minimum size limits to create dynamic and responsive form fields that conform with the page design. +- **[ime-safe-enter-submit](https://github.com/GoogleChrome/modern-web-guidance/blob/main/skills/modern-web-guidance/guides/forms/ime-safe-enter-submit.md)**: Implement keyboard text submission (like enter-to-submit in chat/textareas) safely for IME (Input Method Editor) users to prevent premature submission of incomplete text. - **[required-field-feedback](https://github.com/GoogleChrome/modern-web-guidance/blob/main/skills/modern-web-guidance/guides/forms/required-field-feedback.md)**: Provide error message for required form fields that were skipped or left empty *only* after user interaction, to avoid preemptive errors and ensure feedback is timely and contextually relevant to the user's flow. - **[rich-media-picker](https://github.com/GoogleChrome/modern-web-guidance/blob/main/skills/modern-web-guidance/guides/forms/rich-media-picker.md)**: Create a custom select component whose options can contain complex HTML formatting (e.g. images, icons, and other rich formatting) rather than just plain text. - **[select-menu-interaction](https://github.com/GoogleChrome/modern-web-guidance/blob/main/skills/modern-web-guidance/guides/forms/select-menu-interaction.md)**: Validate that a non-default option has been chosen in a select menu only after the user has interacted with the control. diff --git a/guides/forms/forms/guide.md b/guides/forms/forms/guide.md index 5376dfbbc..e5a7c347b 100644 --- a/guides/forms/forms/guide.md +++ b/guides/forms/forms/guide.md @@ -221,6 +221,7 @@ input { ### Guidelines +- **DO** check `KeyboardEvent.isComposing` before treating the `Enter` key as a submit action in chat or text inputs to ensure IME text composition is not interrupted. See guide {{ GUIDE_REF("ime-safe-enter-submit") }}. - **DO** prevent default navigation on form submit for AJAX (`e.preventDefault()`). - **DO** use `ValidityState` interfaces for real-time validation checks. - **DO** use `aria-expanded` and `aria-controls` for dynamic UI reveals. diff --git a/guides/forms/ime-safe-enter-submit/demo.html b/guides/forms/ime-safe-enter-submit/demo.html new file mode 100644 index 000000000..c1747b09e --- /dev/null +++ b/guides/forms/ime-safe-enter-submit/demo.html @@ -0,0 +1,115 @@ + + + + + + IME-safe enter-to-submit demo + + + + +

IME-safe enter-to-submit

+

Type a message below. Press Enter to submit, or Shift + Enter for a new line.

+ +
+
Welcome! Type a message below.
+
+ +
+
+ + +
+
+ + + + diff --git a/guides/forms/ime-safe-enter-submit/expectations.md b/guides/forms/ime-safe-enter-submit/expectations.md new file mode 100644 index 000000000..782616471 --- /dev/null +++ b/guides/forms/ime-safe-enter-submit/expectations.md @@ -0,0 +1,4 @@ +- Pressing `Enter` key without `Shift` on a textarea when composition is NOT active MUST submit the form or call the send logic. +- Pressing `Enter` key on a textarea when composition IS active (`isComposing` is true), or when the browser signals an IME-consumed keystroke (`event.keyCode === 229`), MUST NOT submit the form or send the message. +- Pressing `Shift+Enter` key on a textarea MUST NOT submit the form and should instead allow normal newline insertion. +- The interface MUST include a semantic, visible submit button (e.g. ` + +``` + +```js +const textarea = document.getElementById('chat-input'); +const form = document.getElementById('chat-form'); + +textarea.addEventListener('keydown', (event) => { + if (event.key === 'Enter' && !event.shiftKey) { + // Prevent the default newline behavior + event.preventDefault(); + + // If the user is composing text, return early. + if (event.isComposing) { + return; + } + + form.requestSubmit(); + } +}); +``` + +Note: Other custom submission shortcuts (such as `Cmd+Enter` or `Ctrl+Enter`) do not conflict with IME confirmation keys and do not require IME safety checks. + +## Accessibility and testing + +1. **Explicit submit button**: Always include a `