Pressing Enter in a text field submits the form — except when the form has no submit button and more than one field, when the “submit” is a <div> styled as a button, or when a stray <button> earlier in the form becomes the default and deletes a row instead of saving. Teams that fight these surprises by blocking Enter everywhere break the fastest way keyboard users complete forms.

The HTML specification defines “implicit submission” precisely, and once its rules are clear, controlling it is straightforward. This page, part of keyboard navigation patterns, explains the rules, fixes the common bugs, and shows how to handle the cases where Enter should not submit — comboboxes, textareas, wizard steps — without breaking it elsewhere.


Context and prerequisites

The rules browsers follow:

  • Pressing Enter in a text-like input (text, email, password, search, tel, url, number, date in most browsers) triggers implicit submission of its form.
  • The form’s default button is the first submit button in tree order (<button> without type, <button type="submit">, <input type="submit">). Implicit submission behaves as if that button was clicked: its click event fires, its name/value are included, its formaction applies.
  • If the form has no submit button, implicit submission still happens if the form has only one field that blocks implicit submission; with several such fields and no submit button, Enter does nothing.
  • Textareas insert a newline; selects, checkboxes and radios do not submit on Enter in most browsers.
  • A <button> with no type attribute is a submit button — the root of many bugs.
What Enter does, by context In a text input in a form with a submit button, Enter clicks the first submit button. In a text input in a form with no submit button and a single text field, Enter submits. With no submit button and several text fields, Enter does nothing. In a textarea, Enter inserts a new line. In a form where a type-less Remove button appears before the real submit button, Enter clicks Remove because it is the first submit button. In a custom combobox with an open list, Enter should select the highlighted option, which requires the widget to handle and stop the event. Context Enter does text input; form has submit button clicks the FIRST submit button no submit button, one text field submits no submit button, several text fields nothing textarea inserts a newline type-less "Remove" before real submit clicks Remove custom combobox, list open widget must select + stop the event

The core pattern: explicit button types and scoped Enter handling

<form id="order" novalidate>
  <!-- A hidden-but-real default button FIRST, so implicit submission always means "save",
       even if other buttons appear earlier visually. -->
  <button type="submit" class="visually-hidden" tabindex="-1" aria-hidden="true">Save order</button>

  <fieldset>
    <legend>Item 1 of 2</legend>
    <label for="qty-1">Quantity</label>
    <input id="qty-1" name="items[0].qty" inputmode="numeric">
    <!-- Every non-submit button declares type="button". -->
    <button type="button" data-action="remove" data-row="1">Remove<span class="visually-hidden"> item 1</span></button>
  </fieldset>

  <button type="button" data-action="add">Add another item</button>
  <button type="submit">Save order</button>
</form>
// Widgets that own Enter (comboboxes, tag inputs) stop it ONLY when they use it.
export function wireCombobox(input: HTMLInputElement, list: HTMLElement, select: (opt: HTMLElement) => void) {
  input.addEventListener("keydown", (e) => {
    if (e.key !== "Enter" || e.isComposing) return;          // IME: Enter confirms composition
    const open = input.getAttribute("aria-expanded") === "true";
    const active = list.querySelector<HTMLElement>("[aria-selected='true']");
    if (open && active) {
      e.preventDefault();                                     // stop implicit submission…
      select(active);                                         // …because Enter chose an option
    }
    // Closed list: let Enter submit the form as usual.
  });
}

// Wizard steps: Enter should mean "Next", not "submit the whole wizard".
export function wireWizardStep(form: HTMLFormElement, next: () => void) {
  form.addEventListener("submit", (e) => {
    e.preventDefault();
    next();                                                   // validate this step, then advance
  });
}

Step-by-step walkthrough

  1. Give every button an explicit type. type="button" for anything that is not a submit — Add, Remove, Show password, Look up address. This single rule removes most accidental submissions.
  2. Make sure the first submit button is the intended default. If layout puts a secondary submit (such as “Save draft”) first in the DOM, add a hidden primary submit button before it, or reorder the DOM and use CSS for visual order.
  3. Do not block Enter globally. A keydown handler that prevents Enter on every input removes the fastest submit path for keyboard users and breaks IME confirmation. Handle validation in the submit handler instead.
  4. Let widgets consume Enter only when they use it. A combobox with an open list uses Enter to choose; with the list closed, Enter should submit. Stop the event conditionally, as in keyboard-accessible combobox validation.
  5. Respect IME composition. e.isComposing is true while Enter confirms a Japanese or Chinese candidate; never submit or select on that keypress.
  6. In wizards, map submit to “Next”. Each step is its own form (or the submit handler advances the step), so Enter validates the current step and moves on, as in validating only the current step.

Why Enter-to-submit is worth protecting

For keyboard and screen-reader users, Enter in the last field is the natural end of a form: it is faster than tabbing to the button, and it works identically across sites. Users with motor impairments who navigate by keyboard benefit most from fewer keystrokes. Breaking it — to “prevent accidental submission” — trades a real, everyday convenience for protection against a problem better solved by validation: an accidental early submit of an incomplete form simply produces an error summary, and nothing is lost. The genuine risks are type-less buttons and Enter inside widgets, and both have targeted fixes.

A type-less button hijacking Enter The user presses Enter in the quantity field of item one. The browser performs implicit submission by clicking the form's first submit button, which is the Remove button because it has no type attribute. Item one is removed and the order is not saved. After adding type button to Remove and every other non-submit button, the same Enter press clicks Save order, which validates and saves. User Browser Remove button Save button Enter in Quantity click first submit button item 1 removed; nothing saved after type="button" fix: click Save

Failure modes and edge cases

1. Buttons inside the form that are not submits

Any <button> without type inside a form submits it on click and can become the default for Enter. Lint for it: an ESLint rule (react/button-has-type) or an HTML validator catches missing types.

2. Forms with no submit button

Search-as-you-type forms and inline editors sometimes omit a submit button. With a single field, Enter still submits — make sure the submit handler does something sensible. With several fields, add a (visually hidden if necessary) submit button, or Enter will do nothing.

3. type="number" and Enter

Most browsers submit on Enter in number fields; some virtual keyboards show “Done” instead of “Go”. Set enterkeyhint="done", "next", "go" or "send" to label the mobile Enter key to match what it will do.

4. Double submission

Enter held down or pressed twice quickly can submit twice. Guard in the submit handler with an in-flight flag, as in disabling submit buttons without hiding the reason.

5. Textareas that should submit

Chat-style inputs often submit on Enter and insert newlines on Shift+Enter. That is a deliberate widget behaviour; state it in a hint, and never apply it to ordinary multi-line fields such as addresses or comments.

Four rules that prevent most Enter bugs Give every non-submit button type button so none becomes the default. Make the intended primary action the first submit button in the DOM, adding a hidden one if layout requires. Let widgets such as comboboxes stop Enter only when they use it, for example to select an option. Ignore Enter while IME composition is active so candidate confirmation does not submit. type="button" On every non-submit button. Default first Primary submit first in DOM. Widgets: conditional Stop Enter only when used. IME aware Skip when isComposing.

Verification checklist


Frequently Asked Questions

Should Enter in the first field of a long form submit it?

Yes — that is the platform behaviour, and the result is simply a validation pass that shows what is missing. Blocking it confuses keyboard users who expect consistency. If early submission is costly, the problem is the cost of a failed submit, not Enter.

How do I make Enter move to the next field instead?

Resist it on the web: it conflicts with platform conventions and assistive technology expectations. The exception is data-entry grids built for heads-down keying, where users are trained on the behaviour; even there, announce it and keep Tab working.

Does a hidden default button cause accessibility issues?

With aria-hidden="true" and tabindex="-1", it is invisible to assistive technology and unreachable by Tab, while still acting as the implicit-submission default. Keep the visible submit button labelled identically so the behaviour is predictable.


Related

← Keyboard Navigation Patterns