Question

How to Hide Number Input Spin Buttons in HTML and CSS

csshtmlinputnumbers

Question

How can I hide the spin buttons that some browsers display for an HTML5 <input type="number"> element?

I want a consistent way, ideally using CSS or JavaScript, to prevent the up/down arrow controls from appearing in browsers such as Chrome.

<input id="test" type="number">

Short Answer

By the end of this page, you will understand how browser spin buttons work on <input type="number">, how to hide them with CSS in common browsers, what limitations exist, and when it may be better to use a different input type altogether.

Concept

<input type="number"> is an HTML form control designed for numeric input. Many browsers add built-in UI controls such as small up/down arrows, often called spin buttons or spinners, to let users increase or decrease the value.

These controls are part of the browser's native rendering of the input. That means:

  • They are not plain HTML elements you can directly remove.
  • Styling them is often browser-specific.
  • There is no single universal CSS rule that works identically everywhere.

Why this matters:

  • You may want a cleaner design without browser-provided arrows.
  • Different browsers render number inputs differently.
  • Form controls often require vendor-prefixed CSS for consistent appearance.

A common solution is:

  • Use appearance-related CSS where supported.
  • Target WebKit/Blink pseudo-elements for Chrome, Edge, and Safari.
  • Adjust Mozilla appearance rules for Firefox.

Even after hiding the visible spin buttons, the input is still usually a number field. It may still:

  • accept numeric validation,
  • respond to arrow keys,
  • respond to mouse wheel changes in some cases.

So hiding the arrows changes the appearance, not necessarily all number-input behavior.

Mental Model

Think of <input type="number"> like a standard numeric text box wrapped in a browser-made control panel.

The browser may attach tiny built-in buttons to the side. You cannot always remove the whole control panel in one standard way, but you can often tell each browser: render this more like a plain text field.

So the goal is not "delete these HTML elements" but rather "ask the browser to display this native control differently."

Take Quiz

Syntax and Examples

The most common CSS approach is to target browser-specific appearance rules.

<input id="test" type="number">
/* Chrome, Safari, Edge, Opera */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Firefox */
input[type="number"] {
  -moz-appearance: textfield;
}

What this does

  • ::-webkit-inner-spin-button and ::-webkit-outer-spin-button target the spinner controls in WebKit/Blink-based browsers.
  • -webkit-appearance: none; hides those controls.
  • margin: 0; helps remove extra spacing left behind in some browsers.
  • -moz-appearance: textfield; makes Firefox render the number input more like a regular text field.

More modern version

Some projects also add the standard appearance property:

input[type="number"] {
  appearance: textfield;
  -moz-appearance: textfield;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

Example with styling

<label for="age">Age</label>
<input id="age" type="number" min="0" max="120" placeholder="Enter age">
input[type="number"] {
  appearance: textfield;
  -moz-appearance: textfield;
  padding: 8px;
  font-size: 16px;
  width: 200px;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

This keeps numeric validation while removing the visible arrows in many browsers.

Step by Step Execution

Consider this example:

<input id="qty" type="number" value="3">
input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

Here is what happens step by step:

  1. The browser reads the HTML and creates a number input.
  2. Because the input is type="number", the browser may decide to render built-in spin buttons.
  3. The CSS selector input[type="number"] matches the field itself.
  4. appearance: textfield and -moz-appearance: textfield tell supporting browsers to display it more like a normal text box.
  5. In WebKit/Blink browsers, the pseudo-elements ::-webkit-outer-spin-button and ::-webkit-inner-spin-button match the spinner UI parts.
  6. -webkit-appearance: none removes their default visible styling.
  7. The input still remains a number input, so browser validation and numeric semantics still apply.

If the user types abc, the browser may reject it or mark the field invalid depending on the browser and form behavior.

If the user presses the up arrow key, the value may still increase, because that behavior belongs to the number input itself, not just the visible spin buttons.

Real World Use Cases

Developers hide number-input spin buttons in cases like these:

  • Custom design systems: the browser arrows do not match the app's visual style.
  • Mobile-friendly forms: the team wants a cleaner field and relies on native numeric keyboards instead.
  • Checkout forms: quantity, ZIP code, OTP, or pricing fields may need a simpler appearance.
  • Admin dashboards: numeric filters and settings inputs may use custom increment/decrement buttons instead of native ones.
  • Embedded widgets: compact UIs often remove default controls to save space.

Example scenarios:

  • A shopping cart uses custom + and - buttons around a quantity input.
  • A finance form accepts amounts but wants all fields to look visually identical.
  • A settings page uses JavaScript validation and prefers a uniform style across browsers.
Take Quiz

Real Codebase Usage

In real projects, developers usually do more than just hide the arrows.

Common patterns

  • Design-system reset: remove browser-specific styling so all form fields start from a predictable baseline.
  • Guarded validation: keep type="number" for browser validation, but add custom checks for range, decimals, or required values.
  • Custom controls: hide native spinners and provide separate increment/decrement buttons.
  • Input constraints: combine min, max, and step with styling.
  • Event handling: prevent accidental wheel-based changes in fields like prices or quantities.

Example: custom quantity field

<div class="quantity-control">
  <button type="button" id="decrease">-</button>
  <input id="quantity" type="number" min="1" value="1">
  <button type="button" id="increase">+</button>
</div>
input[type="number"] {
  appearance: textfield;
  -moz-appearance: textfield;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
const input = document.getElementById('quantity');
const increase = document.getElementById('increase');
const decrease = document.getElementById('decrease');

increase.addEventListener('click', () => {
  input.stepUp();
});

decrease.addEventListener('click', () => {
  if (Number(input.value) > Number(input.min || 0)) {
    input.stepDown();
  }
});

This is common in real codebases because it preserves number semantics while using custom UI.

Common Mistakes

1. Expecting one universal CSS rule

A beginner might try:

input[type="number"] {
  display: textfield;
}

This does not work because display is the wrong property.

Use browser appearance properties instead.

2. Forgetting browser-specific pseudo-elements

Broken example:

input[type="number"]::spin-button {
  display: none;
}

There is no standard ::spin-button selector for this use case.

Use:

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
}

3. Hiding the arrows but forgetting behavior still exists

Even if the arrows are hidden:

  • arrow keys may still change the value,
  • the mouse wheel may still change the value,
  • validation rules still apply.

If you need to stop wheel changes, you may add JavaScript:

const input = document.getElementById('test');

input.addEventListener('wheel', (event) => {
  event.preventDefault();
}, { passive: false });

Use this carefully, because it affects usability.

4. Using type="text" without considering trade-offs

Some developers switch to:

<input type="text">

This removes number-field behavior, but you also lose built-in numeric validation and number-specific browser behavior.

5. Assuming all browsers behave exactly the same

Native form controls are one of the least uniform parts of the web platform. Always test in the browsers your users actually use.

Comparisons

ApproachKeeps numeric semanticsHides visible arrowsCross-browser consistencyNotes
type="number" with CSS spinner-hiding rulesYesUsuallyModerateMost common solution
type="number" with no custom CSSYesNoLowBrowser decides appearance
type="text" with custom validationNo built-in number semanticsYesHigh for appearanceMore manual validation needed
Custom UI with buttons + type="number"YesYesModerateGood for quantity controls

type="number" vs type="text"

Featuretype="number"type="text"
Built-in numeric validationYesNo
Native spin buttonsOften yesNo
Numeric keyboard on some devicesOften yesNot guaranteed
Custom visual controlHarderEasier
Accepts only numeric intent semanticallyYesNo

If you only want to hide the arrows, keep type="number" and style it. If you need full visual and behavioral control, type="text" plus validation may be more appropriate.

Take Quiz

Cheat Sheet

<input type="number">
/* Firefox */
input[type="number"] {
  appearance: textfield;
  -moz-appearance: textfield;
}

/* Chrome, Safari, Edge, Opera */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

Key points

  • Spin buttons are browser-native UI.
  • There is no single fully universal CSS rule.
  • WebKit/Blink browsers use ::-webkit-inner-spin-button and ::-webkit-outer-spin-button.
  • Firefox often uses -moz-appearance: textfield.
  • Hiding arrows does not remove number input behavior.
  • If needed, use JavaScript to stop wheel-based changes.
  • Test in real browsers before shipping.

FAQ

Can I completely remove number input spin buttons in every browser with one CSS rule?

No. Native form controls are browser-specific, so you usually need different CSS rules for different engines.

Does hiding the arrows change the input from a number field into a text field?

No. It still remains type="number" unless you change the HTML.

Why do the arrows disappear in one browser but not another?

Because browsers render native controls differently and support different appearance properties and pseudo-elements.

Should I use JavaScript to hide the spin buttons?

Usually no. CSS is the normal approach for hiding the visible controls. JavaScript is more useful for changing behavior, such as preventing wheel-based value changes.

Is type="text" better if I want full styling control?

Sometimes, yes. But you lose built-in numeric validation and number semantics, so you must replace that behavior yourself.

Can users still change the value with the keyboard after I hide the arrows?

Often yes. Hiding the visible buttons does not necessarily disable arrow-key behavior.

Do hidden spin buttons affect accessibility?

They can. If you remove native controls, make sure users still have a clear and usable way to enter or adjust numeric values.

Take Quiz

Mini Project

Description

Build a small quantity input component for a shopping cart. The number field should keep numeric behavior, but the browser's native spin buttons should be hidden. Instead, users will use custom + and - buttons to change the value.

Goal

Create a styled number input with hidden native spinners and custom increment/decrement controls.

Requirements

  • Create an HTML number input with a minimum value of 1.
  • Hide the native spin buttons in common browsers using CSS.
  • Add a minus button to decrease the value.
  • Add a plus button to increase the value.
  • Prevent the value from going below the minimum.
Take Quiz

Keep learning

Related questions

View more