NumberField
A field for a number, in the format of the locale, with buttons that step it.
2 guests, a budget of 120.
<script>
import { $bind, $signal } from 'brumate/signals';
import Button from '@brumate/ui/Button.brm';
import Group from '@brumate/ui/Group.brm';
import Input from '@brumate/ui/Input.brm';
import Label from '@brumate/ui/Label.brm';
import NumberField from '@brumate/ui/NumberField.brm';
let guests = $signal(2);
let budget = $signal(120);
</script>
<div class="ui-stack">
<NumberField class="ui-field" minValue=(1) maxValue=(12) value=$bind(guests)>
<Label>Guests</Label>
<Group class="ui-number">
<Button slot="decrement" class="ui-step">−</Button>
<Input class="ui-input" />
<Button slot="increment" class="ui-step">+</Button>
</Group>
</NumberField>
<NumberField class="ui-field" minValue=(0) step=(10) value=$bind(budget) formatOptions=({ style: 'currency', currency: 'USD' })>
<Label>Budget</Label>
<Group class="ui-number">
<Button slot="decrement" class="ui-step">−</Button>
<Input class="ui-input" />
<Button slot="increment" class="ui-step">+</Button>
</Group>
</NumberField>
</div>
<p>{guests} guests, a budget of {budget}.</p>
<NumberField minValue=(0) step=(5) value=$bind(width)>
<Label>Width</Label>
<Group>
<Button slot="decrement">−</Button>
<Input />
<Button slot="increment">+</Button>
</Group>
</NumberField>
- A
NumberFieldholds aLabel, aGroupwith anInputand twoButtonelements withslot="decrement"andslot="increment", and can hold aTextwithslot="description"and aFieldError. valueis the number, orNaNwhen the field is empty. It starts its own state, or binds with$bind, andonChangegets each change. See State.namesends the number with its form, also before the code of the page loads. It sends the number as it reads in the input, so Enter sends what was typed.- A reset of the form gives back the first number.
isRequiredasks the browser to check the field on a submit, and theFieldErrorshows the message.- It shows
data-disabled,data-readonly,data-invalidanddata-required.
Format
- The number shows in the format of the locale, from an I18nProvider, and of
formatOptions, the options ofIntl.NumberFormat, such as{ style: 'currency', currency: 'EUR' }or{ style: 'percent' }. - Typing keeps only text that can become a number, such as
-or1,in German. - When focus leaves the input, or on Enter, the field reads the number, keeps it between
minValueandmaxValue, moves it to the neareststepwhen there is one, and formats it again.
Stepping
- ArrowUp and ArrowDown, PageUp and PageDown, and the Buttons step the number by
step, 1 by default, or 1% for a percent. A number off the steps moves to the nearest one first. - A held Button steps again after 400 milliseconds, 600 for a touch, and then every 60 milliseconds. Focus stays in the input.
- Home and End go to the minimum and the maximum, when there are. Without a limit, they move the caret.
- A key with Shift, Ctrl, Alt or Meta does not step. The arrow keys with Shift still do not select text, since the keys are prevented before the code loads.
- A field with
isDisabledorisReadOnlyprevents no keys. - The wheel steps the number while the input has focus, unless
isWheelDisabled. - A Button is disabled when a step would pass the end of the range, and with
isDisabledorisReadOnly.
Names
The Buttons are named "Increase" and "Decrease" with the Label, or with the aria-label of the field, such as "Increase Quantity". aria-label and aria-labelledby on the field name its input. The Buttons are out of the order of Tab, and control the input. The input has the role of a text box with the description "Number field", as in React Aria, since a spin button cannot take focus with VoiceOver.