Skip to content

Commit 739d7f1

Browse files
authored
Docs for NumberField (#1522)
1 parent ff60780 commit 739d7f1

File tree

4 files changed

+348
-23
lines changed

4 files changed

+348
-23
lines changed

packages/@adobe/spectrum-css-temp/components/stepper/index.css

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,30 +84,31 @@ governing permissions and limitations under the License.
8484
}
8585
}
8686

87-
.spectrum-Stepper-button--stepUp {
88-
grid-area: increment;
89-
border-start-end-radius: var(--spectrum-border-radius);
90-
padding-block-start: calc(var(--spectrum-button-padding-y) + 1px);
91-
padding-block-end: calc(var(--spectrum-button-padding-y) - .5px);
92-
}
93-
94-
.spectrum-Stepper-button--stepDown {
95-
grid-area: decrement;
96-
border-block-start: none;
97-
border-end-end-radius: var(--spectrum-border-radius);
98-
padding-block-end: calc(var(--spectrum-button-padding-y) + 1px);
99-
padding-block-start: calc(var(--spectrum-button-padding-y) - .5px);
87+
.spectrum-Stepper {
88+
.spectrum-Stepper-button--stepUp {
89+
grid-area: increment;
90+
border-start-end-radius: var(--spectrum-border-radius);
91+
padding-block-start: calc(var(--spectrum-button-padding-y) + 1px);
92+
padding-block-end: calc(var(--spectrum-button-padding-y) - .5px);
93+
}
10094

101-
&:focus {
95+
.spectrum-Stepper-button--stepDown {
96+
grid-area: decrement;
10297
border-block-start: none;
103-
}
104-
}
98+
border-end-end-radius: var(--spectrum-border-radius);
99+
padding-block-end: calc(var(--spectrum-button-padding-y) + 1px);
100+
padding-block-start: calc(var(--spectrum-button-padding-y) - .5px);
105101

106-
.spectrum-Stepper-field {
107-
grid-area: field;
102+
&:focus {
103+
border-block-start: none;
104+
}
105+
}
106+
.spectrum-Stepper-field {
107+
grid-area: field;
108108

109-
inline-size: unset;
110-
min-inline-size: var(--spectrum-stepper-input-min-width);
109+
inline-size: unset;
110+
min-inline-size: var(--spectrum-stepper-input-min-width);
111+
}
111112
}
112113

113114
.spectrum-Stepper--showStepper {
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
<!-- Copyright 2020 Adobe. All rights reserved.
2+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License. You may obtain a copy
4+
of the License at http://www.apache.org/licenses/LICENSE-2.0
5+
Unless required by applicable law or agreed to in writing, software distributed under
6+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
7+
OF ANY KIND, either express or implied. See the License for the specific language
8+
governing permissions and limitations under the License. -->
9+
10+
import {Layout} from '@react-spectrum/docs';
11+
export default Layout;
12+
13+
import docs from 'docs:@react-spectrum/numberfield';
14+
import {HeaderInfo, PropTable} from '@react-spectrum/docs';
15+
import packageData from '@react-spectrum/numberfield/package.json';
16+
17+
```jsx import
18+
import {NumberField} from '@react-spectrum/numberfield';
19+
import {Flex} from '@react-spectrum/layout';
20+
```
21+
22+
---
23+
category: Forms
24+
keywords: [number field, input]
25+
---
26+
27+
# NumberField
28+
29+
<p>{docs.exports.NumberField.description}</p>
30+
31+
<HeaderInfo
32+
packageData={packageData}
33+
componentNames={['NumberField']}
34+
sourceData={[]} />
35+
36+
## Example
37+
38+
```tsx example
39+
<NumberField label="Width" defaultValue={1024} minValue={0} />
40+
```
41+
42+
## Value
43+
44+
A NumberField's `value` is empty by default, but an initial, uncontrolled, value can be provided using the `defaultValue` prop.
45+
Alternatively, a controlled value can be provided using the `value` prop.
46+
47+
```tsx example
48+
function Example() {
49+
let [value, setValue] = React.useState(15);
50+
51+
return (
52+
<Flex gap="size-150" wrap>
53+
<NumberField
54+
label="Cookies (Uncontrolled)"
55+
defaultValue={15}
56+
minValue={0} />
57+
58+
<NumberField
59+
label="Cookies (Controlled)"
60+
value={value}
61+
onChange={setValue}
62+
minValue={0} />
63+
</Flex>
64+
);
65+
}
66+
```
67+
68+
## Labeling
69+
70+
A visual label should be provided for the NumberField using the `label` prop. If the NumberField is required, the `isRequired` and
71+
`necessityIndicator` props can be used to show a required state.
72+
73+
```tsx example
74+
<Flex gap="size-150" wrap>
75+
<NumberField label="Cookies" minValue={0} />
76+
<NumberField label="Cookies" isRequired necessityIndicator="icon" minValue={0} />
77+
<NumberField label="Cookies" isRequired necessityIndicator="label" minValue={0} />
78+
<NumberField label="Cookies" necessityIndicator="label" minValue={0} />
79+
</Flex>
80+
```
81+
82+
### Accessibility
83+
84+
If a visible label isn't specified, an `aria-label` must be provided to the NumberField for
85+
accessibility. If the field is labeled by a separate element, an `aria-labelledby` prop must be provided using
86+
the `id` of the labeling element instead.
87+
88+
### Internationalization
89+
90+
In order to internationalize a NumberField, a localized string should be passed to the `label` or `aria-label` prop.
91+
When the `necessityIndicator` prop is set to `"label"`, a localized string will be provided for `"(required)"` or `"(optional)"` automatically.
92+
93+
## Number formatting
94+
95+
The NumberField value can be formatted by using the `formatOptions` prop.
96+
`formatOptions` is compatible with the option parameter of [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) and is applied based on the current locale.
97+
Currently only standard notation is supported, though scientific, engineering, and compact notation may be supported in the future.
98+
99+
NumberField supports three numeral systems; Latin, Arabic-Indic, and Han decimal. Regardless of the locale, these three
100+
can be parsed from typed input. Initial rendering will appear in the [default numeral system](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/numberingSystem) for the locale unless explicitly overridden.
101+
102+
### Decimals
103+
104+
The following example uses the `signDisplay` option to include the plus sign for positive numbers, for example to display an offset from some value.
105+
In addition, it always displays a minimum of 1 digit after the decimal point, and allows up to 2 fraction digits.
106+
If the user enters more than 2 fraction digits, the result will be rounded.
107+
108+
```tsx example
109+
<NumberField
110+
label="Adjust exposure"
111+
formatOptions={{
112+
signDisplay: 'exceptZero',
113+
minimumFractionDigits: 1,
114+
maximumFractionDigits: 2
115+
}}
116+
defaultValue={0} />
117+
```
118+
119+
### Percentages
120+
121+
The `style: 'percent'` option can be passed to the `formatOptions` prop to treat the value as a percentage. In this mode,
122+
the value is multiplied by 100 before it is displayed, i.e. `0.45` is displayed as `45%`. The reverse is also true: when the
123+
user enters a value, the `onChange` event will be triggered with the entered value divided by 100. When the percent option
124+
is enabled, the default step automatically changes to `0.01` such that incrementing and decrementing occurs by `1%`. This can
125+
be overridden with the `step` prop. [See below](#step-values) for details.
126+
127+
```tsx example
128+
<NumberField
129+
label="Sales tax"
130+
formatOptions={{style: 'percent'}}
131+
minValue={0}
132+
defaultValue={0.05} />
133+
```
134+
135+
### Currency values
136+
137+
The `style: 'currency'` option can be passed to the `formatOptions` prop to treat the value as a currency value. The `currency`
138+
option must also be passed to set the currency code (e.g. `USD`) to use. In addition, the `currencyDisplay` option can be
139+
used to choose whether to display the currency symbol, currency code, or currency name. Finally, the `currencySign` option
140+
can be set to `accounting` to use accounting notation for negative numbers, which uses parentheses rather than a minus sign
141+
in some locales.
142+
143+
If you need to allow the user to change the currency, you should include a separate dropdown next to the NumberField.
144+
The NumberField itself will not determine the currency from the user input.
145+
146+
```tsx example
147+
<NumberField
148+
label="Transaction amount"
149+
defaultValue={45}
150+
formatOptions={{
151+
style: 'currency',
152+
currency: 'EUR',
153+
currencyDisplay: 'code',
154+
currencySign: 'accounting'
155+
}} />
156+
```
157+
158+
### Units
159+
160+
The `style: 'unit'` option can be passed to the `formatOptions` prop to format the value with a unit of measurement. The `unit`
161+
option must also be passed to set which unit to use (e.g. `inch`). In addition, the `unitDisplay` option can be used to choose
162+
whether to display the unit in long, short, or narrow format.
163+
164+
If you need to allow the user to change the unit, you should include a separate dropdown next to the number field.
165+
The number field itself will not determine the unit from the user input.
166+
167+
**Note:** The `unit` style is not currently supported in Safari. A [polyfill](https://formatjs.io/docs/polyfills/intl-numberformat/)
168+
may be necessary.
169+
170+
```tsx example
171+
<NumberField
172+
label="Package width"
173+
defaultValue={4}
174+
minValue={0}
175+
formatOptions={{
176+
style: 'unit',
177+
unit: 'inch',
178+
unitDisplay: 'long'
179+
}} />
180+
```
181+
182+
## Minimum and maximum values
183+
184+
The `minValue` and `maxValue` props can be used to limit the entered value to a specific range. The value will be clamped
185+
when the user blurs the input field. In addition, the increment and decrement buttons will be disabled when the value is
186+
within one `step` value from the bounds ([see below](#step-values) for info about steps). Ranges can be open ended by only
187+
providing either `minValue` or `maxValue` rather than both.
188+
189+
If a valid range is known ahead of time, it is a good idea to provide it to `NumberField` so it can optimize the experience.
190+
For example, when the minimum value is greater than or equal to zero, it is possible to use a numeric keyboard on iOS rather
191+
than a full text keyboard (necessary to enter a minus sign).
192+
193+
```tsx example
194+
<NumberField
195+
label="Enter your age"
196+
minValue={0} />
197+
```
198+
199+
## Step values
200+
201+
The `step` prop can be used to snap the value to certain increments. If there is a `minValue` defined, the steps are calculated
202+
starting from the minimum. For example, if `minValue={2}`, and `step={3}`, the valid step values would be 2, 5, 8, 11, etc. If no
203+
`minValue` is defined, the steps are calculated starting from zero and extending in both directions. In other words, such that the
204+
values are evenly divisible by the step. A `step` can be any positive decimal. If no `step` is defined, any decimal value may be typed, but incrementing and decrementing
205+
snaps the value to an integer.
206+
207+
If the user types a value that is between two steps and blurs the input, the value will be snapped to the nearest step. When
208+
incrementing or decrementing, the value is snapped to the nearest step that is higher or lower, respectively.
209+
When incrementing or decrementing from an empty field, the value starts at the `minValue` or `maxValue`, respectively, if defined.
210+
Otherwise, the value starts from `0`.
211+
212+
```tsx example
213+
<Flex direction="column" gap="size-150">
214+
<NumberField
215+
label="Step"
216+
step={10} />
217+
<NumberField
218+
label="Step + minValue"
219+
minValue={2}
220+
step={3} />
221+
<NumberField
222+
label="Step + minValue + maxValue"
223+
minValue={2}
224+
maxValue={21}
225+
step={3} />
226+
</Flex>
227+
```
228+
229+
## Events
230+
231+
NumberField accepts an `onChange` prop which is triggered whenever the value is committed by the user. This happens on blur of the field
232+
or on interaction with the stepper functionality, arrow keys or stepper buttons.
233+
For a full list of supported events, see the [Props](#props) table below.
234+
235+
The example below uses `onChange` to update a separate `pre` element with the same values entered into the NumberField.
236+
```tsx example
237+
function Example() {
238+
let [value, setValue] = React.useState();
239+
240+
return (
241+
<Flex direction="column" gap="size-150">
242+
<NumberField
243+
onChange={setValue}
244+
label="Number of cookies to buy"
245+
minValue={0} />
246+
<pre>How many cookies you are ordering: {isNaN(value) ? 0 : value}</pre>
247+
</Flex>
248+
);
249+
}
250+
```
251+
252+
## Validation
253+
254+
NumberFields can display a validation state to communicate to the user whether the current value is valid or invalid.
255+
Implement your own validation logic in your app and pass either `"valid"` or `"invalid"` to the NumberField via the `validationState` prop.
256+
257+
The example below illustrates how one would validate if the user has entered a [FizzBuzz](https://en.wikipedia.org/wiki/Fizz_buzz) number into the NumberField.
258+
```tsx example
259+
function Example() {
260+
let [value, setValue] = React.useState(15);
261+
let isValid = React.useMemo(() => value % 3 === 0 && value % 5 === 0, [value]);
262+
263+
return (
264+
<NumberField
265+
validationState={isValid ? 'valid' : 'invalid'}
266+
value={value}
267+
onChange={setValue}
268+
label="FizzBuzz values only"
269+
/>
270+
);
271+
}
272+
```
273+
274+
## Props
275+
276+
<PropTable component={docs.exports.NumberField} links={docs.links} />
277+
278+
## Visual options
279+
280+
### Quiet
281+
282+
```tsx example
283+
<NumberField label="Cookies" isQuiet minValue={0} />
284+
```
285+
286+
### Hidden Steppers
287+
288+
NumberField stepper buttons are optional.
289+
290+
```tsx example
291+
<NumberField label="Cookies" hideStepper minValue={0} />
292+
```
293+
294+
### Disabled
295+
296+
```tsx example
297+
<NumberField label="Cookies" isDisabled minValue={0} />
298+
```
299+
300+
### Read only
301+
302+
The `isReadOnly` boolean prop makes the NumberField's text content immutable. Unlike `isDisabled` the NumberField remains focusable
303+
and the contents can still be copied. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.
304+
305+
```tsx example
306+
<NumberField label="Cookies" defaultValue={15} isReadOnly minValue={0} />
307+
```
308+
309+
### Label alignment and position
310+
[View guidelines](https://spectrum.adobe.com/page/text-field/#Label-position)
311+
312+
By default, the label is positioned above the NumberField. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the NumberField and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.
313+
314+
```tsx example
315+
<NumberField label="Cookies" labelPosition="side" labelAlign="end" minValue={0} />
316+
```
317+
318+
### Custom width
319+
320+
[View guidelines](https://spectrum.adobe.com/page/text-field/#Width)
321+
322+
```tsx example
323+
<NumberField label="Cookies" width="size-3600" maxWidth="100%" minValue={0} />
324+
```

packages/@react-spectrum/numberfield/src/NumberField.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ const NumberFieldInput = React.forwardRef(function NumberFieldInput(props: Numbe
164164
});
165165

166166
/**
167-
* Numberfield allow entering of numbers with steppers to increment and decrement that value.
167+
* NumberFields allow users to enter a number, and increment or decrement the value using stepper buttons.
168168
*/
169169
let _NumberField = React.forwardRef(NumberField);
170170
export {_NumberField as NumberField};

packages/@react-types/numberfield/src/index.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export interface AriaNumberFieldProps extends NumberFieldProps, DOMProps, AriaLa
3737
incrementAriaLabel?: string
3838
}
3939

40-
export interface SpectrumNumberFieldProps extends AriaNumberFieldProps, StyleProps, SpectrumLabelableProps, Omit<AriaNumberFieldProps, 'placeholder'> {
41-
/** Whether the number field should be displayed with a quiet style. */
40+
export interface SpectrumNumberFieldProps extends Omit<AriaNumberFieldProps, 'placeholder'>, StyleProps, SpectrumLabelableProps {
41+
/** Whether the numberfield should be displayed with a quiet style. */
4242
isQuiet?: boolean,
4343
/** Whether to hide the increment and decrement buttons. */
4444
hideStepper?: boolean

0 commit comments

Comments
 (0)