Skip to content

feat(ui5-number-input): introduce NumberInput component#13799

Open
GDamyanov wants to merge 14 commits into
mainfrom
number-input
Open

feat(ui5-number-input): introduce NumberInput component#13799
GDamyanov wants to merge 14 commits into
mainfrom
number-input

Conversation

@GDamyanov

@GDamyanov GDamyanov commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Introduces a new ui5-number-input component as the dedicated numeric input primitive, and refactors ui5-step-input to be built on top of it.

New Component: ui5-number-input

A numeric input field ui5-number-input has been extracted as a standalone component. It handles all numeric input logic internally:

  • Number formatting via locale-aware NumberFormat
  • Min/max validation with value-state-change event (preventable)
  • Keyboard navigation: arrow keys, Ctrl/Shift modifiers, Page Up/Down
  • Mouse wheel support
  • Spin button acceleration on long-press
  • Increment/decrement buttons (opt-in via _showStepButtons)
  • Form association support
  • Full accessibility (ARIA labels, value state messages)

Refactored: ui5-step-input

ui5-step-input is now a thin wrapper around ui5-number-input, delegating all numeric logic to it

A new private property is added in the ui5-number-input:

_showStepButtons is a @Private, noAttribute boolean property on ui5-number-input (defaults to false) that controls whether the increment/decrement buttons are rendered. When false, ui5-number-input renders as a plain numeric input with no step buttons — suitable for standalone use. ui5-step-input sets _showStepButtons={true} in its template, which activates the buttons and the associated CSS modifier class (ui5-number-input-root--with-buttons). This means the step button UI lives entirely inside ui5-number-input; ui5-step-input does not render any buttons of its own.

@GDamyanov GDamyanov self-assigned this Jul 8, 2026
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 8, 2026 11:29 — with GitHub Actions Inactive
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

👋 Heads-up: dev close is in effect

Thanks for the contribution! This repository is currently in dev close ahead of release next (scheduled 2026-07-09, UTC). See the release schedule for the full timeline.

This PR appears to introduce public-API changes (detected by diffing the Custom Elements Manifest against the latest published version on npm):

@ui5/webcomponents

  • ➕ added element: NumberInput
  • ➕ added property: accessibleName
  • ➕ added property: accessibleNameRef
  • ➕ added property: disabled
  • ➕ added property: max
  • ➕ added property: min
  • ➕ added property: name
  • ➕ added property: placeholder
  • ➕ added property: readonly
  • ➕ added property: required
  • ➕ added property: step
  • ➕ added property: value
  • ➕ added property: valuePrecision
  • ➕ added property: valueState
  • ➕ added event: change
  • ➕ added event: input
  • ➕ added event: value-state-change
  • ➕ added slot: valueStateMessage
  • ➕ added attribute: accessible-name
  • ➕ added attribute: accessible-name-ref
  • ➕ added attribute: disabled
  • ➕ added attribute: max
  • ➕ added attribute: min
  • ➕ added attribute: name
  • ➕ added attribute: placeholder
  • ➕ added attribute: readonly
  • ➕ added attribute: required
  • ➕ added attribute: step
  • ➕ added attribute: value
  • ➕ added attribute: value-precision
  • ➕ added attribute: value-state
  • 🔄 changed attribute value-state (type)

Could you please hold off on merging into main until the release ships? Public-API changes are best landed in the next dev cycle so they don't slip into the release at the last minute. Once the release is out, this PR is good to go.

If this change must ship in the current release, please request a review from one or two members of @UI5/ui5-team-webc so the team can sign off explicitly.

💬 False positive? If you believe this PR doesn't actually change the public API (e.g. only internal refactoring, or an entry the detector mis-attributed), please reply on this thread — your feedback helps us improve the detection during this trial run.

Posted automatically by the Dev Close Notice workflow.

@sap-ui5-webcomponents-release

Copy link
Copy Markdown

@GDamyanov GDamyanov temporarily deployed to netlify-preview July 8, 2026 11:40 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 8, 2026 11:44 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 8, 2026 12:04 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 8, 2026 12:36 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 8, 2026 12:39 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 8, 2026 13:40 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 8, 2026 14:05 — with GitHub Actions Inactive
@GDamyanov GDamyanov requested a review from hinzzx July 8, 2026 14:26
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 9, 2026 14:16 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 9, 2026 19:39 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 10, 2026 06:21 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 10, 2026 06:49 — with GitHub Actions Inactive
@GDamyanov GDamyanov temporarily deployed to netlify-preview July 10, 2026 07:26 — with GitHub Actions Inactive

@hinzzx hinzzx left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • We should also register the NumberInput in ReactPlayground;

_onButtonFocusOut() {
setTimeout(() => {
if (!this._inputFocused && !this.shadowRoot!.activeElement) {
this.inputOuter.removeAttribute("focused");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must be property/template-driven. Using remove/setAttribute is a forbidden pattern.

Just use this.focused = false, and add the focused={this.focused} in the tempalte.

} from "@ui5/webcomponents-base/dist/Keys.js";
import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import type ValueState, then wherever used, replace with template string literals.

ValueState.None → `${ValueState.None}`

this._validate();
this._setButtonState();
this.focused = true;
this.inputOuter.setAttribute("focused", "");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it should also be property/template-driven. We should not use remove/setattribute.

return {
patternMismatch: this.value !== 0 && !this._isValueWithCorrectPrecision,
rangeOverflow: this.max !== undefined && this.value >= this.max,
rangeUnderflow: this.min !== undefined && this.value <= this.min,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

form-validity boundaries are inverted: rangeOverflow: value >= max, rangeUnderflow: value <= min,
this means a value exactly at min or max (e.g. max=10, value=10) is flagged form-invalid; clamping to max leaves it permanently invalid.

Think we should remove the =

onFocusOut={this._onfocusout}
onWheel={this._onMouseWheel}
<NumberInput
_showStepButtons={true}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shadow DOM surface changed.

Step-input's internals went from [ui5-input] (.ui5-step-input-root/-input) to a nested [ui5-number-input].

Any consumer CSS, querySelector, or ::part targeting the old internals breaks.

I think this is a BREAKING CHANGE, which we should document somewhere.

bubbles: true,
cancelable: true,
})
@event("_request-submit", {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

internal event is used as the public coordination channel between two public components

_setDefaultInputValueIfNeeded() {
if (this.input.value === "") {
const defaultValue = this._formatNumber(this.min || 0);
this.input.value = defaultValue;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same applies here

return !Number.isNaN(parsedValue) && !/, {2,}/.test(typedValue);
}

_decSpin(e: MouseEvent) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the whole spin functionality lack tests

}

onExitDOM() {
this._cleanupLanguageChangeHandler();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should reset the spin there.

this._resetSpin()

--_ui5_number_input_error_focused_background: var(--sapField_Focus_Background);
--_ui5_number_input_button_state_hover_background_color: var(--sapField_Background);
--_ui5_number_input_error_hover_background: var(--sapField_Background);
--_ui5_number_input_border_style: 1px solid var(--sapField_BorderColor);;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two ;s

--_ui5_number_input_error_warning_information_border_style: none;
--_ui5_number_input_after_border_style: var(--_ui5_input_error_warning_border_style);
--_ui5_number_input_error_background_color: var(--_ui5_input_input_background_color);
--_ui5_number_input_error_background_color_hover: var(--_ui5_number_input_input_error_background_color);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not used anywhere

@@ -0,0 +1,32 @@
:host {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add: --_ui5_number_input_min_width: 7.25rem;

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.

2 participants