diff --git a/change/@fluentui-web-components-7901265e-589d-4d51-8bb8-320a376cb79d.json b/change/@fluentui-web-components-7901265e-589d-4d51-8bb8-320a376cb79d.json
new file mode 100644
index 00000000000000..238972491fccce
--- /dev/null
+++ b/change/@fluentui-web-components-7901265e-589d-4d51-8bb8-320a376cb79d.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "add current-value attribute to text-input",
+ "packageName": "@fluentui/web-components",
+ "email": "863023+radium-v@users.noreply.github.com",
+ "dependentChangeType": "patch"
+}
diff --git a/packages/web-components/docs/api-report.md b/packages/web-components/docs/api-report.md
index 6a49a130b20222..34a685264c2c0d 100644
--- a/packages/web-components/docs/api-report.md
+++ b/packages/web-components/docs/api-report.md
@@ -792,6 +792,9 @@ export class BaseTextInput extends FASTElement {
control: HTMLInputElement;
// @internal
controlLabel: HTMLLabelElement;
+ currentValue: string;
+ // @internal
+ currentValueChanged(prev: string, next: string): void;
// @internal
defaultSlottedNodes: Node[];
// @internal
diff --git a/packages/web-components/src/text-input/text-input.spec.ts b/packages/web-components/src/text-input/text-input.spec.ts
index f16fa96736308c..839ec937ef5a7b 100644
--- a/packages/web-components/src/text-input/text-input.spec.ts
+++ b/packages/web-components/src/text-input/text-input.spec.ts
@@ -833,4 +833,85 @@ test.describe('TextInput', () => {
await expect(control).toBeFocused();
});
});
+
+ test('should reset the value to an empty string when the form is reset', async ({ page }) => {
+ const element = page.locator('fluent-text-input');
+ const control = element.locator('input');
+ const reset = page.locator('button');
+
+ await page.setContent(/* html */ `
+
+ `);
+
+ await expect(control).toHaveValue('');
+
+ await control.fill('hello');
+
+ await reset.click();
+
+ await expect(control).toHaveValue('');
+ });
+
+ test('should change the `value` property when the `current-value` attribute changes', async ({ page }) => {
+ const element = page.locator('fluent-text-input');
+
+ await page.setContent(/* html */ `
+
+ `);
+
+ await element.evaluate(node => {
+ node.setAttribute('current-value', 'foo');
+ });
+
+ await expect(element).toHaveJSProperty('value', 'foo');
+ });
+
+ test('should change the `value` property when the `currentValue` property changes', async ({ page }) => {
+ const element = page.locator('fluent-text-input');
+
+ await page.setContent(/* html */ `
+
+ `);
+
+ await element.evaluate((node: TextInput) => {
+ node.currentValue = 'foo';
+ });
+
+ await expect(element).toHaveJSProperty('value', 'foo');
+ });
+
+ test('should set the `current-value` attribute to match the `value` property', async ({ page }) => {
+ const element = page.locator('fluent-text-input');
+
+ await page.setContent(/* html */ `
+
+ `);
+
+ await expect(element).not.toHaveAttribute('current-value');
+
+ await element.evaluate((node: TextInput) => {
+ node.value = 'foo';
+ });
+
+ await expect(element).toHaveAttribute('current-value', 'foo');
+ });
+
+ test('should set the `currentValue` property to match the `value` property', async ({ page }) => {
+ const element = page.locator('fluent-text-input');
+
+ await page.setContent(/* html */ `
+
+ `);
+
+ await expect(element).toHaveJSProperty('currentValue', undefined);
+
+ await element.evaluate((node: TextInput) => {
+ node.value = 'foo';
+ });
+
+ await expect(element).toHaveJSProperty('currentValue', 'foo');
+ });
});
diff --git a/packages/web-components/src/text-input/text-input.ts b/packages/web-components/src/text-input/text-input.ts
index 0d844c5e3d52e5..ab4e16b6e97154 100644
--- a/packages/web-components/src/text-input/text-input.ts
+++ b/packages/web-components/src/text-input/text-input.ts
@@ -44,6 +44,27 @@ export class BaseTextInput extends FASTElement {
@attr({ mode: 'boolean' })
public autofocus!: boolean;
+ /**
+ * The current value of the input.
+ * @public
+ * @remarks
+ * HTML Attribute: `current-value`
+ */
+ @attr({ attribute: 'current-value' })
+ public currentValue!: string;
+
+ /**
+ * Tracks the current value of the input.
+ *
+ * @param prev - the previous value
+ * @param next - the next value
+ *
+ * @internal
+ */
+ currentValueChanged(prev: string, next: string): void {
+ this.value = next;
+ }
+
/**
* The default slotted content. This is the content that appears in the text field label.
*
@@ -274,13 +295,6 @@ export class BaseTextInput extends FASTElement {
@attr
public type: TextInputType = TextInputType.text;
- /**
- * The current value of the input.
- *
- * @internal
- */
- private _value: string = this.initialValue;
-
/**
* A reference to the internal input element.
*
@@ -346,14 +360,14 @@ export class BaseTextInput extends FASTElement {
*/
public get value(): string {
Observable.track(this, 'value');
- return this._value;
+ return this.currentValue;
}
public set value(value: string) {
- this._value = value;
+ this.currentValue = value;
if (this.$fastController.isConnected) {
- this.control.value = value;
+ this.control.value = value ?? '';
this.setFormValue(value);
this.setValidity();
Observable.notify(this, 'value');