diff --git a/change/@fluentui-web-components-6b5e7aec-7c00-49cf-8a0d-66fc803d4b59.json b/change/@fluentui-web-components-6b5e7aec-7c00-49cf-8a0d-66fc803d4b59.json
new file mode 100644
index 00000000000000..941dcfc1d499b4
--- /dev/null
+++ b/change/@fluentui-web-components-6b5e7aec-7c00-49cf-8a0d-66fc803d4b59.json
@@ -0,0 +1,7 @@
+{
+ "type": "minor",
+ "comment": "created and add number-field files",
+ "packageName": "@fluentui/web-components",
+ "email": "khamu@microsoft.com",
+ "dependentChangeType": "patch"
+}
diff --git a/packages/web-components/docs/api-report.md b/packages/web-components/docs/api-report.md
index f99d6eeb2927ed..f6b5021fe3fd38 100644
--- a/packages/web-components/docs/api-report.md
+++ b/packages/web-components/docs/api-report.md
@@ -31,6 +31,7 @@ import { Listbox } from '@microsoft/fast-foundation';
import { ListboxOption } from '@microsoft/fast-foundation';
import { Menu } from '@microsoft/fast-foundation';
import { MenuItem } from '@microsoft/fast-foundation';
+import { NumberField } from '@microsoft/fast-foundation';
import { Radio } from '@microsoft/fast-foundation';
import { RadioGroup } from '@microsoft/fast-foundation';
import { Select } from '@microsoft/fast-foundation';
@@ -696,6 +697,13 @@ export class FluentMenu extends Menu {
export class FluentMenuItem extends MenuItem {
}
+// @public
+export class FluentNumberField extends NumberField {
+ appearance: NumberFieldAppearance;
+ // @internal (undocumented)
+ connectedCallback(): void;
+}
+
// @public
export class FluentOption extends ListboxOption {
}
@@ -1222,6 +1230,12 @@ export const neutralOutlineRest: SwatchRecipe;
// @public
export const neutralOutlineRestBehavior: CSSCustomPropertyBehavior;
+// @public
+export type NumberFieldAppearance = 'filled' | 'outline';
+
+// @public
+export const NumberFieldStyles: import("@microsoft/fast-element").ElementStyles;
+
// @public
export const OptionStyles: import("@microsoft/fast-element").ElementStyles;
diff --git a/packages/web-components/src/index.ts b/packages/web-components/src/index.ts
index ef629d167159fe..389f4cac3ce751 100644
--- a/packages/web-components/src/index.ts
+++ b/packages/web-components/src/index.ts
@@ -18,6 +18,7 @@ export * from './listbox';
export * from './listbox-option';
export * from './menu/';
export * from './menu-item/';
+export * from './number-field/';
export * from './progress/';
export * from './radio/';
export * from './radio-group/';
diff --git a/packages/web-components/src/number-field/fixtures/number-field.html b/packages/web-components/src/number-field/fixtures/number-field.html
new file mode 100644
index 00000000000000..534b49c9832d71
--- /dev/null
+++ b/packages/web-components/src/number-field/fixtures/number-field.html
@@ -0,0 +1,113 @@
+
+ Number field
+ Default
+
+ Label
+
+ Hide step
+ Label
+
+ With value
+
+
+ With min 1 and max 10
+
+
+ 0.1 stepping
+
+
+ Full Width
+
+
+ Placeholder
+
+
+
+ Required
+
+
+
+ Disabled
+
+ label
+
+
+
+ Read only
+
+ label
+
+
+ Autofocus
+ autofocus
+
+
+ Maxlength
+ maxlength
+
+
+ Minlength
+ minlength
+
+
+ With start
+
+
+
+
+
+ With end
+
+
+
+
+ Filled
+ Default
+
+ label
+
+ Placeholder
+
+
+
+ Required
+
+
+
+ Disabled
+
+ label
+
+
+
+ Read only
+
+
+ label
+
+
+
+ Visual vs audio label
+
+ Visible label
+
+
+
+ With aria-label
+
+
+
+
diff --git a/packages/web-components/src/number-field/index.ts b/packages/web-components/src/number-field/index.ts
new file mode 100644
index 00000000000000..086a274cb15f07
--- /dev/null
+++ b/packages/web-components/src/number-field/index.ts
@@ -0,0 +1,58 @@
+import { attr, customElement } from '@microsoft/fast-element';
+import { NumberField, NumberFieldTemplate as template } from '@microsoft/fast-foundation';
+import { NumberFieldStyles as styles } from './number-field.styles';
+
+/**
+ * Number field appearances
+ * @public
+ */
+export type NumberFieldAppearance = 'filled' | 'outline';
+
+/**
+ * The Fluent Number Field Custom Element. Implements {@link @microsoft/fast-foundation#NumberField},
+ * {@link @microsoft/fast-foundation#NumberFieldTemplate}
+ *
+ *
+ * @public
+ * @remarks
+ * HTML Element: \
+ *
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/delegatesFocus | delegatesFocus}
+ */
+@customElement({
+ name: 'fluent-number-field',
+ shadowOptions: {
+ delegatesFocus: true,
+ mode: 'closed',
+ },
+ styles,
+ template,
+})
+export class FluentNumberField extends NumberField {
+ /**
+ * The appearance of the element.
+ *
+ * @public
+ * @remarks
+ * HTML Attribute: appearance
+ */
+ @attr
+ public appearance: NumberFieldAppearance;
+
+ /**
+ * @internal
+ */
+ public connectedCallback() {
+ super.connectedCallback();
+
+ if (!this.appearance) {
+ this.appearance = 'outline';
+ }
+ }
+}
+
+/**
+ * Styles for NumberField
+ * @public
+ */
+export const NumberFieldStyles = styles;
diff --git a/packages/web-components/src/number-field/number-field.stories.ts b/packages/web-components/src/number-field/number-field.stories.ts
new file mode 100644
index 00000000000000..404110f745bf87
--- /dev/null
+++ b/packages/web-components/src/number-field/number-field.stories.ts
@@ -0,0 +1,24 @@
+import addons from '@storybook/addons';
+import { STORY_RENDERED } from '@storybook/core-events';
+import NumberFieldTemplate from './fixtures/number-field.html';
+import './index';
+
+addons.getChannel().addListener(STORY_RENDERED, (name: string) => {
+ if (name.toLowerCase().startsWith('number-field')) {
+ document.querySelectorAll('.form').forEach(el => {
+ if (el instanceof HTMLFormElement) {
+ el.onsubmit = event => {
+ event.preventDefault();
+ const form: HTMLFormElement = document.forms['myForm'];
+ console.log(form.elements['fname'].value, 'value of input');
+ };
+ }
+ });
+ }
+});
+
+export default {
+ title: 'Number Field',
+};
+
+export const NumberField = () => NumberFieldTemplate;
diff --git a/packages/web-components/src/number-field/number-field.styles.ts b/packages/web-components/src/number-field/number-field.styles.ts
new file mode 100644
index 00000000000000..7cf3c867c5e464
--- /dev/null
+++ b/packages/web-components/src/number-field/number-field.styles.ts
@@ -0,0 +1,223 @@
+import { css } from '@microsoft/fast-element';
+import { disabledCursor, display, focusVisible, forcedColorsStylesheetBehavior } from '@microsoft/fast-foundation';
+import { SystemColors } from '@microsoft/fast-web-utilities';
+import {
+ accentFillActiveBehavior,
+ accentFillHoverBehavior,
+ accentFillRestBehavior,
+ heightNumber,
+ neutralFillHoverBehavior,
+ neutralFillInputHoverBehavior,
+ neutralFillInputRestBehavior,
+ neutralFillRestBehavior,
+ neutralFocusBehavior,
+ neutralForegroundRestBehavior,
+ neutralOutlineRestBehavior,
+} from '../styles/index';
+
+export const NumberFieldStyles = css`
+ ${display('inline-block')} :host {
+ font-family: var(--body-font);
+ outline: none;
+ user-select: none;
+ }
+
+ .root {
+ box-sizing: border-box;
+ position: relative;
+ display: flex;
+ flex-direction: row;
+ color: ${neutralForegroundRestBehavior.var};
+ background: ${neutralFillInputRestBehavior.var};
+ border-radius: calc(var(--corner-radius) * 1px);
+ border: calc(var(--outline-width) * 1px) solid ${accentFillRestBehavior.var};
+ height: calc(${heightNumber} * 1px);
+ }
+
+ .control {
+ -webkit-appearance: none;
+ font: inherit;
+ background: transparent;
+ border: 0;
+ color: inherit;
+ height: calc(100% - 4px);
+ width: 100%;
+ margin-top: auto;
+ margin-bottom: auto;
+ border: none;
+ padding: 0 calc(var(--design-unit) * 2px + 1px);
+ font-size: var(--type-ramp-base-font-size);
+ line-height: var(--type-ramp-base-line-height);
+ }
+
+ .control:hover,
+ .control:${focusVisible},
+ .control:disabled,
+ .control:active {
+ outline: none;
+ }
+
+ .controls {
+ opacity: 0;
+ }
+
+ .label {
+ display: block;
+ color: ${neutralForegroundRestBehavior.var};
+ cursor: pointer;
+ font-size: var(--type-ramp-base-font-size);
+ line-height: var(--type-ramp-base-line-height);
+ margin-bottom: 4px;
+ }
+
+ .label__hidden {
+ display: none;
+ visibility: hidden;
+ }
+
+ .start,
+ .end {
+ margin: auto;
+ fill: currentcolor;
+ }
+
+ .step-up,
+ .step-down {
+ padding: 2px 10px;
+ cursor: pointer;
+ }
+
+ .step-up:before,
+ .step-down:before {
+ content: '';
+ display: block;
+ border: solid transparent 6px;
+ }
+
+ .step-up:before {
+ border-bottom-color: ${neutralForegroundRestBehavior.var};
+ }
+
+ .step-down:before {
+ border-top-color: ${neutralForegroundRestBehavior.var};
+ }
+
+ ::slotted(svg) {
+ ${
+ /* Glyph size and margin-left is temporary -
+ replace when adaptive typography is figured out */ ''
+ } width: 16px;
+ height: 16px;
+ }
+
+ .start {
+ display: flex;
+ margin-inline-start: 11px;
+ }
+
+ .end {
+ display: flex;
+ margin-inline-end: 11px;
+ }
+
+ :host(:hover:not([disabled])) .root {
+ background: ${neutralFillInputHoverBehavior.var};
+ border-color: ${accentFillHoverBehavior.var};
+ }
+
+ :host(:active:not([disabled])) .root {
+ background: ${neutralFillInputHoverBehavior.var};
+ border-color: ${accentFillActiveBehavior.var};
+ }
+
+ :host(:focus-within:not([disabled])) .root {
+ border-color: ${neutralFocusBehavior.var};
+ box-shadow: 0 0 0 1px ${neutralFocusBehavior.var} inset;
+ }
+
+ :host(:hover:not([disabled])) .controls,
+ :host(:focus-within:not([disabled])) .controls {
+ opacity: 1;
+ }
+
+ :host([appearance="filled"]) .root {
+ background: ${neutralFillRestBehavior.var};
+ }
+
+ :host([appearance="filled"]:hover:not([disabled])) .root {
+ background: ${neutralFillHoverBehavior.var};
+ }
+
+ :host([disabled]) .label,
+ :host([readonly]) .label,
+ :host([readonly]) .control,
+ :host([disabled]) .control {
+ cursor: ${disabledCursor};
+ }
+
+ :host([disabled]) {
+ opacity: var(--disabled-opacity);
+ }
+
+ :host([disabled]) .control {
+ border-color: ${neutralOutlineRestBehavior.var};
+ }
+`.withBehaviors(
+ accentFillActiveBehavior,
+ accentFillHoverBehavior,
+ accentFillRestBehavior,
+ neutralFillHoverBehavior,
+ neutralFillInputHoverBehavior,
+ neutralFillInputRestBehavior,
+ neutralFillRestBehavior,
+ neutralFocusBehavior,
+ neutralForegroundRestBehavior,
+ neutralOutlineRestBehavior,
+ forcedColorsStylesheetBehavior(
+ css`
+ .root,
+ :host([appearance='filled']) .root {
+ forced-color-adjust: none;
+ background: ${SystemColors.Field};
+ border-color: ${SystemColors.FieldText};
+ }
+ :host(:hover:not([disabled])) .root,
+ :host([appearance='filled']:hover:not([disabled])) .root,
+ :host([appearance='filled']:hover) .root {
+ background: ${SystemColors.Field};
+ border-color: ${SystemColors.Highlight};
+ }
+ :host(:focus-within:enabled) .root {
+ border-color: ${SystemColors.Highlight};
+ box-shadow: 0 0 0 1px ${SystemColors.Highlight} inset;
+ }
+ .control,
+ ::placeholder,
+ ::-webkit-input-placeholder {
+ color: ${SystemColors.FieldText};
+ }
+ .step-up:before {
+ border-bottom-color: ${SystemColors.FieldText};
+ }
+ .step-down:before {
+ border-top-color: ${SystemColors.FieldText};
+ }
+ .start,
+ .end {
+ fill: ${SystemColors.FieldText};
+ }
+ :host([disabled]) {
+ opacity: 1;
+ }
+ :host([disabled]) .root,
+ :host([appearance='filled']:hover[disabled]) .root {
+ border-color: ${SystemColors.GrayText};
+ background: ${SystemColors.Field};
+ }
+ :host([disabled]) ::placeholder,
+ :host([disabled]) ::-webkit-input-placeholder {
+ color: ${SystemColors.GrayText};
+ }
+ `,
+ ),
+);