diff --git a/src/auth/ha-auth-flow.ts b/src/auth/ha-auth-flow.ts
index 4799fbc155..5075c3963f 100644
--- a/src/auth/ha-auth-flow.ts
+++ b/src/auth/ha-auth-flow.ts
@@ -7,7 +7,7 @@ import {
css,
} from "lit-element";
import "@material/mwc-button";
-import "../components/ha-form";
+import "../components/ha-form/ha-form";
import "../components/ha-markdown";
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
import { AuthProvider } from "../data/auth";
diff --git a/src/components/ha-form.js b/src/components/ha-form.js
deleted file mode 100644
index f6dfe613ee..0000000000
--- a/src/components/ha-form.js
+++ /dev/null
@@ -1,265 +0,0 @@
-import "@polymer/paper-checkbox/paper-checkbox";
-import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
-import "@polymer/paper-icon-button/paper-icon-button";
-import "@polymer/paper-input/paper-input";
-import "@polymer/paper-item/paper-item";
-import "@polymer/paper-listbox/paper-listbox";
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "./ha-paper-slider";
-import { EventsMixin } from "../mixins/events-mixin";
-
-/*
- * @appliesMixin EventsMixin
- */
-class HaForm extends EventsMixin(PolymerElement) {
- static get template() {
- return html`
-
-
-
- [[computeError(error.base, schema)]]
-
-
-
-
-
-
-
-
- [[computeError(error, schema)]]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- [[computeLabel(schema)]]
-
-
-
-
-
-
-
-
-
-
-
- [[computeSuffix(schema)]]
-
-
-
-
-
-
[[computeLabel(schema)]]
-
-
-
-
-
-
-
- [[_optionLabel(item)]]
-
-
-
-
-
- `;
- }
-
- static get properties() {
- return {
- data: {
- type: Object,
- notify: true,
- },
- schema: Object,
- error: Object,
-
- // A function that computes the label to be displayed for a given
- // schema object.
- computeLabel: {
- type: Function,
- value: () => (schema) => schema && schema.name,
- },
-
- // A function that computes the suffix to be displayed for a given
- // schema object.
- computeSuffix: {
- type: Function,
- value: () => (schema) =>
- schema &&
- schema.description &&
- schema.description.unit_of_measurement,
- },
-
- // A function that computes an error message to be displayed for a
- // given error ID, and relevant schema object
- computeError: {
- type: Function,
- value: () => (error, schema) => error, // eslint-disable-line no-unused-vars
- },
- };
- }
-
- focus() {
- const input = this.shadowRoot.querySelector(
- "ha-form, paper-input, ha-paper-slider, paper-checkbox, paper-dropdown-menu"
- );
-
- if (!input) {
- return;
- }
-
- input.focus();
- }
-
- _isArray(val) {
- return Array.isArray(val);
- }
-
- _isRange(schema) {
- return "valueMin" in schema && "valueMax" in schema;
- }
-
- _equals(a, b) {
- return a === b;
- }
-
- _includes(a, b) {
- return a.indexOf(b) >= 0;
- }
-
- _getValue(obj, item) {
- if (obj) {
- return obj[item.name];
- }
- return null;
- }
-
- _valueChanged(ev) {
- let value = ev.detail.value;
- if (ev.model.item.type === "integer") {
- value = Number(ev.detail.value);
- }
- this.set(["data", ev.model.item.name], value);
- }
-
- _passwordFieldType(unmaskedPassword) {
- return unmaskedPassword ? "text" : "password";
- }
-
- _passwordFieldIcon(unmaskedPassword) {
- return unmaskedPassword ? "hass:eye-off" : "hass:eye";
- }
-
- _optionValue(item) {
- return Array.isArray(item) ? item[0] : item;
- }
-
- _optionLabel(item) {
- return Array.isArray(item) ? item[1] : item;
- }
-}
-
-customElements.define("ha-form", HaForm);
diff --git a/src/components/ha-form/ha-form-boolean.ts b/src/components/ha-form/ha-form-boolean.ts
new file mode 100644
index 0000000000..5921cd3e43
--- /dev/null
+++ b/src/components/ha-form/ha-form-boolean.ts
@@ -0,0 +1,70 @@
+import {
+ customElement,
+ LitElement,
+ html,
+ property,
+ TemplateResult,
+ CSSResult,
+ css,
+ query,
+} from "lit-element";
+import {
+ HaFormElement,
+ HaFormBooleanData,
+ HaFormBooleanSchema,
+} from "./ha-form";
+import { fireEvent } from "../../common/dom/fire_event";
+
+import "@polymer/paper-checkbox/paper-checkbox";
+// Not duplicate, is for typing
+// tslint:disable-next-line
+import { PaperCheckboxElement } from "@polymer/paper-checkbox/paper-checkbox";
+
+@customElement("ha-form-boolean")
+export class HaFormBoolean extends LitElement implements HaFormElement {
+ @property() public schema!: HaFormBooleanSchema;
+ @property() public data!: HaFormBooleanData;
+ @property() public label!: string;
+ @property() public suffix!: string;
+ @query("paper-checkbox") private _input?: HTMLElement;
+
+ public focus() {
+ if (this._input) {
+ this._input.focus();
+ }
+ }
+
+ protected render(): TemplateResult {
+ return html`
+
+ ${this.label}
+
+ `;
+ }
+
+ private _valueChanged(ev: Event) {
+ fireEvent(
+ this,
+ "value-changed",
+ {
+ value: (ev.target as PaperCheckboxElement).checked,
+ },
+ { bubbles: false }
+ );
+ }
+
+ static get styles(): CSSResult {
+ return css`
+ paper-checkbox {
+ display: inline-block;
+ padding: 22px 0;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-form-boolean": HaFormBoolean;
+ }
+}
diff --git a/src/components/ha-form/ha-form-float.ts b/src/components/ha-form/ha-form-float.ts
new file mode 100644
index 0000000000..0d2279ea72
--- /dev/null
+++ b/src/components/ha-form/ha-form-float.ts
@@ -0,0 +1,65 @@
+import {
+ customElement,
+ LitElement,
+ html,
+ property,
+ TemplateResult,
+ query,
+} from "lit-element";
+import { HaFormElement, HaFormFloatData, HaFormFloatSchema } from "./ha-form";
+import { fireEvent } from "../../common/dom/fire_event";
+
+import "@polymer/paper-input/paper-input";
+// Not duplicate, is for typing
+// tslint:disable-next-line
+import { PaperInputElement } from "@polymer/paper-input/paper-input";
+
+@customElement("ha-form-float")
+export class HaFormFloat extends LitElement implements HaFormElement {
+ @property() public schema!: HaFormFloatSchema;
+ @property() public data!: HaFormFloatData;
+ @property() public label!: string;
+ @property() public suffix!: string;
+ @query("paper-input") private _input?: HTMLElement;
+
+ public focus() {
+ if (this._input) {
+ this._input.focus();
+ }
+ }
+
+ protected render(): TemplateResult {
+ return html`
+
+ ${this.suffix}
+
+ `;
+ }
+
+ private _valueChanged(ev: Event) {
+ const value = Number((ev.target as PaperInputElement).value);
+ if (this.data === value) {
+ return;
+ }
+ fireEvent(
+ this,
+ "value-changed",
+ {
+ value,
+ },
+ { bubbles: false }
+ );
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-form-float": HaFormFloat;
+ }
+}
diff --git a/src/components/ha-form/ha-form-integer.ts b/src/components/ha-form/ha-form-integer.ts
new file mode 100644
index 0000000000..4b38678e52
--- /dev/null
+++ b/src/components/ha-form/ha-form-integer.ts
@@ -0,0 +1,85 @@
+import {
+ customElement,
+ LitElement,
+ html,
+ property,
+ TemplateResult,
+ query,
+} from "lit-element";
+import {
+ HaFormElement,
+ HaFormIntegerData,
+ HaFormIntegerSchema,
+} from "./ha-form";
+import { fireEvent } from "../../common/dom/fire_event";
+
+import "../ha-paper-slider";
+import "@polymer/paper-input/paper-input";
+// Not duplicate, is for typing
+// tslint:disable-next-line
+import { PaperInputElement } from "@polymer/paper-input/paper-input";
+import { PaperSliderElement } from "@polymer/paper-slider/paper-slider";
+
+@customElement("ha-form-integer")
+export class HaFormInteger extends LitElement implements HaFormElement {
+ @property() public schema!: HaFormIntegerSchema;
+ @property() public data!: HaFormIntegerData;
+ @property() public label!: string;
+ @property() public suffix!: string;
+ @query("paper-input ha-paper-slider") private _input?: HTMLElement;
+
+ public focus() {
+ if (this._input) {
+ this._input.focus();
+ }
+ }
+
+ protected render(): TemplateResult {
+ return "valueMin" in this.schema && "valueMax" in this.schema
+ ? html`
+
+ ${this.label}
+
+
+ `
+ : html`
+
+ `;
+ }
+
+ private _valueChanged(ev: Event) {
+ const value = Number(
+ (ev.target as PaperInputElement | PaperSliderElement).value
+ );
+ if (this.data === value) {
+ return;
+ }
+ fireEvent(
+ this,
+ "value-changed",
+ {
+ value,
+ },
+ { bubbles: false }
+ );
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-form-integer": HaFormInteger;
+ }
+}
diff --git a/src/components/ha-form/ha-form-select.ts b/src/components/ha-form/ha-form-select.ts
new file mode 100644
index 0000000000..25a13abd23
--- /dev/null
+++ b/src/components/ha-form/ha-form-select.ts
@@ -0,0 +1,78 @@
+import {
+ customElement,
+ LitElement,
+ html,
+ property,
+ TemplateResult,
+ query,
+} from "lit-element";
+import { HaFormElement, HaFormSelectData, HaFormSelectSchema } from "./ha-form";
+import { fireEvent } from "../../common/dom/fire_event";
+
+import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
+import "@polymer/paper-listbox/paper-listbox";
+import "@polymer/paper-item/paper-item";
+
+@customElement("ha-form-select")
+export class HaFormSelect extends LitElement implements HaFormElement {
+ @property() public schema!: HaFormSelectSchema;
+ @property() public data!: HaFormSelectData;
+ @property() public label!: string;
+ @property() public suffix!: string;
+ @query("paper-dropdown-menu") private _input?: HTMLElement;
+
+ public focus() {
+ if (this._input) {
+ this._input.focus();
+ }
+ }
+
+ protected render(): TemplateResult {
+ return html`
+
+
+ ${this.schema.options!.map(
+ (item) => html`
+
+ ${this._optionLabel(item)}
+
+ `
+ )}
+
+
+ `;
+ }
+
+ private _optionValue(item) {
+ return Array.isArray(item) ? item[0] : item;
+ }
+
+ private _optionLabel(item) {
+ return Array.isArray(item) ? item[1] : item;
+ }
+
+ private _valueChanged(ev: CustomEvent) {
+ if (!ev.detail.value) {
+ return;
+ }
+ fireEvent(
+ this,
+ "value-changed",
+ {
+ value: ev.detail.value.itemValue,
+ },
+ { bubbles: false }
+ );
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-form-select": HaFormSelect;
+ }
+}
diff --git a/src/components/ha-form/ha-form-string.ts b/src/components/ha-form/ha-form-string.ts
new file mode 100644
index 0000000000..82a3db8131
--- /dev/null
+++ b/src/components/ha-form/ha-form-string.ts
@@ -0,0 +1,93 @@
+import {
+ customElement,
+ LitElement,
+ html,
+ property,
+ TemplateResult,
+ query,
+} from "lit-element";
+
+import { HaFormElement, HaFormStringData, HaFormStringSchema } from "./ha-form";
+import { fireEvent } from "../../common/dom/fire_event";
+
+import "@polymer/paper-input/paper-input";
+import "@polymer/paper-icon-button/paper-icon-button";
+// Not duplicate, is for typing
+// tslint:disable-next-line
+import { PaperInputElement } from "@polymer/paper-input/paper-input";
+
+@customElement("ha-form-string")
+export class HaFormString extends LitElement implements HaFormElement {
+ @property() public schema!: HaFormStringSchema;
+ @property() public data!: HaFormStringData;
+ @property() public label!: string;
+ @property() public suffix!: string;
+ @property() private _unmaskedPassword = false;
+ @query("paper-input") private _input?: HTMLElement;
+
+ public focus() {
+ if (this._input) {
+ this._input.focus();
+ }
+ }
+
+ protected render(): TemplateResult {
+ return this.schema.name.includes("password")
+ ? html`
+
+
+
+
+ `
+ : html`
+
+ `;
+ }
+
+ private _toggleUnmaskedPassword(ev: Event) {
+ this._unmaskedPassword = (ev.target as any).active;
+ }
+
+ private _valueChanged(ev: Event) {
+ const value = (ev.target as PaperInputElement).value;
+ if (this.data === value) {
+ return;
+ }
+ fireEvent(
+ this,
+ "value-changed",
+ {
+ value,
+ },
+ { bubbles: false }
+ );
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-form-string": HaFormString;
+ }
+}
diff --git a/src/components/ha-form/ha-form.ts b/src/components/ha-form/ha-form.ts
new file mode 100644
index 0000000000..a8fe7d813d
--- /dev/null
+++ b/src/components/ha-form/ha-form.ts
@@ -0,0 +1,225 @@
+import {
+ customElement,
+ LitElement,
+ html,
+ property,
+ query,
+ CSSResult,
+ css,
+ PropertyValues,
+} from "lit-element";
+
+import "./ha-form-string";
+import "./ha-form-integer";
+import "./ha-form-float";
+import "./ha-form-boolean";
+import "./ha-form-select";
+import { fireEvent } from "../../common/dom/fire_event";
+
+export type HaFormSchema =
+ | HaFormStringSchema
+ | HaFormIntegerSchema
+ | HaFormFloatSchema
+ | HaFormBooleanSchema
+ | HaFormSelectSchema;
+
+export interface HaFormBaseSchema {
+ name: string;
+ default?: HaFormData;
+ required?: boolean;
+ optional?: boolean;
+ description?: { suffix?: string };
+}
+
+export interface HaFormIntegerSchema extends HaFormBaseSchema {
+ type: "integer";
+ default?: HaFormIntegerData;
+ valueMin?: number;
+ valueMax?: number;
+}
+
+export interface HaFormSelectSchema extends HaFormBaseSchema {
+ type: "select";
+ options?: string[];
+}
+
+export interface HaFormFloatSchema extends HaFormBaseSchema {
+ type: "float";
+}
+
+export interface HaFormStringSchema extends HaFormBaseSchema {
+ type: "string";
+}
+
+export interface HaFormBooleanSchema extends HaFormBaseSchema {
+ type: "boolean";
+}
+
+export interface HaFormDataContainer {
+ [key: string]: HaFormData;
+}
+
+export type HaFormData =
+ | HaFormStringData
+ | HaFormIntegerData
+ | HaFormFloatData
+ | HaFormBooleanData
+ | HaFormSelectData;
+
+export type HaFormStringData = string;
+export type HaFormIntegerData = number;
+export type HaFormFloatData = number;
+export type HaFormBooleanData = boolean;
+export type HaFormSelectData = string;
+
+export interface HaFormElement extends LitElement {
+ schema: HaFormSchema;
+ data: HaFormDataContainer | HaFormData;
+ label?: string;
+ suffix?: string;
+}
+
+@customElement("ha-form")
+export class HaForm extends LitElement implements HaFormElement {
+ @property() public data!: HaFormDataContainer | HaFormData;
+ @property() public schema!: HaFormSchema;
+ @property() public error;
+ @property() public computeError?: (schema: HaFormSchema, error) => string;
+ @property() public computeLabel?: (schema: HaFormSchema) => string;
+ @property() public computeSuffix?: (schema: HaFormSchema) => string;
+ @query("ha-form") private _childForm?: HaForm;
+ @query("#element") private _elementContainer?: HTMLDivElement;
+
+ public focus() {
+ const input = this._childForm
+ ? this._childForm
+ : this._elementContainer
+ ? this._elementContainer.lastChild
+ : undefined;
+
+ if (!input) {
+ return;
+ }
+
+ (input as HTMLElement).focus();
+ }
+
+ protected render() {
+ if (Array.isArray(this.schema)) {
+ return html`
+ ${this.error && this.error.base
+ ? html`
+
+ ${this._computeError(this.error.base, this.schema)}
+
+ `
+ : ""}
+ ${this.schema.map(
+ (item) => html`
+
+ `
+ )}
+ `;
+ }
+
+ return html`
+ ${this.error
+ ? html`
+
+ ${this._computeError(this.error, this.schema)}
+
+ `
+ : ""}
+
+ `;
+ }
+
+ protected updated(changedProperties: PropertyValues) {
+ const schemaChanged = changedProperties.has("schema");
+ const oldSchema = schemaChanged
+ ? changedProperties.get("schema")
+ : undefined;
+ if (
+ !Array.isArray(this.schema) &&
+ schemaChanged &&
+ (!oldSchema || (oldSchema as HaFormSchema).type !== this.schema.type)
+ ) {
+ const element = document.createElement(
+ `ha-form-${this.schema.type}`
+ ) as HaFormElement;
+ element.schema = this.schema;
+ element.data = this.data;
+ element.label = this._computeLabel(this.schema);
+ element.suffix = this._computeSuffix(this.schema);
+ if (this._elementContainer!.lastChild) {
+ this._elementContainer!.removeChild(this._elementContainer!.lastChild);
+ }
+ this._elementContainer!.append(element);
+ } else if (this._elementContainer && this._elementContainer.lastChild) {
+ const element = this._elementContainer!.lastChild as HaFormElement;
+ element.schema = this.schema;
+ element.data = this.data;
+ element.label = this._computeLabel(this.schema);
+ element.suffix = this._computeSuffix(this.schema);
+ }
+ }
+
+ private _computeLabel(schema: HaFormSchema) {
+ return this.computeLabel
+ ? this.computeLabel(schema)
+ : schema
+ ? schema.name
+ : "";
+ }
+
+ private _computeSuffix(schema: HaFormSchema) {
+ return this.computeSuffix
+ ? this.computeSuffix(schema)
+ : schema && schema.description
+ ? schema.description.suffix
+ : "";
+ }
+
+ private _computeError(error, schema: HaFormSchema) {
+ return this.computeError ? this.computeError(error, schema) : error;
+ }
+
+ private _getValue(obj, item) {
+ if (obj) {
+ return obj[item.name];
+ }
+ return null;
+ }
+
+ private _valueChanged(ev: CustomEvent) {
+ ev.stopPropagation();
+ const schema = (ev.target as HaFormElement).schema;
+ const data = this.data as HaFormDataContainer;
+ data[schema.name] = ev.detail.value;
+ fireEvent(this, "value-changed", {
+ value: { ...data },
+ });
+ }
+
+ static get styles(): CSSResult {
+ return css`
+ .error {
+ color: var(--error-color);
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-form": HaForm;
+ }
+}
diff --git a/src/dialogs/config-flow/dialog-data-entry-flow.ts b/src/dialogs/config-flow/dialog-data-entry-flow.ts
index c10900e340..a85f3b11bd 100644
--- a/src/dialogs/config-flow/dialog-data-entry-flow.ts
+++ b/src/dialogs/config-flow/dialog-data-entry-flow.ts
@@ -14,7 +14,7 @@ import "@polymer/paper-tooltip/paper-tooltip";
import "@polymer/paper-spinner/paper-spinner";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
-import "../../components/ha-form";
+import "../../components/ha-form/ha-form";
import "../../components/ha-markdown";
import "../../resources/ha-style";
import "../../components/dialog/ha-paper-dialog";
diff --git a/src/dialogs/config-flow/step-flow-form.ts b/src/dialogs/config-flow/step-flow-form.ts
index 4eb73f5c02..3b3d2fbad3 100644
--- a/src/dialogs/config-flow/step-flow-form.ts
+++ b/src/dialogs/config-flow/step-flow-form.ts
@@ -12,10 +12,9 @@ import "@material/mwc-button";
import "@polymer/paper-tooltip/paper-tooltip";
import "@polymer/paper-spinner/paper-spinner";
-import "../../components/ha-form";
+import "../../components/ha-form/ha-form";
import "../../components/ha-markdown";
import "../../resources/ha-style";
-import { PolymerChangedEvent, applyPolymerEvent } from "../../polymer-types";
import { HomeAssistant } from "../../types";
import { fireEvent } from "../../common/dom/fire_event";
import { configFlowContentStyles } from "./styles";
@@ -69,7 +68,7 @@ class StepFlowForm extends LitElement {
${this.flowConfig.renderShowFormStepDescription(this.hass, this.step)}
): void {
- this._stepData = applyPolymerEvent(ev, this._stepData);
+ private _stepDataChanged(ev: CustomEvent): void {
+ this._stepData = ev.detail.value;
}
private _labelCallback = (field: FieldSchema): string =>
diff --git a/src/panels/config/js/condition/device.tsx b/src/panels/config/js/condition/device.tsx
index 1fd9a8385e..17032c479d 100644
--- a/src/panels/config/js/condition/device.tsx
+++ b/src/panels/config/js/condition/device.tsx
@@ -2,7 +2,7 @@ import { h, Component } from "preact";
import "../../../../components/device/ha-device-picker";
import "../../../../components/device/ha-device-condition-picker";
-import "../../../../components/ha-form";
+import "../../../../components/ha-form/ha-form";
import {
fetchDeviceConditionCapabilities,
@@ -64,9 +64,9 @@ export default class DeviceCondition extends Component {
{extraFieldsData && (
)}
@@ -98,15 +98,9 @@ export default class DeviceCondition extends Component {
}
private _extraFieldsChanged(ev) {
- if (!ev.detail.path) {
- return;
- }
- const item = ev.detail.path.replace("data.", "");
- const value = ev.detail.value || undefined;
-
this.props.onChange(this.props.index, {
...this.props.condition,
- [item]: value,
+ ...ev.detail.value,
});
}
diff --git a/src/panels/config/js/script/device.tsx b/src/panels/config/js/script/device.tsx
index 344ff96253..3ae41ba5a8 100644
--- a/src/panels/config/js/script/device.tsx
+++ b/src/panels/config/js/script/device.tsx
@@ -2,7 +2,7 @@ import { h, Component } from "preact";
import "../../../../components/device/ha-device-picker";
import "../../../../components/device/ha-device-action-picker";
-import "../../../../components/ha-form";
+import "../../../../components/ha-form/ha-form";
import {
fetchDeviceActionCapabilities,
@@ -117,15 +117,9 @@ export default class DeviceActionEditor extends Component<
}
private _extraFieldsChanged(ev) {
- if (!ev.detail.path) {
- return;
- }
- const item = ev.detail.path.replace("data.", "");
- const value = ev.detail.value || undefined;
-
this.props.onChange(this.props.index, {
...this.props.action,
- [item]: value,
+ ...ev.detail.value,
});
}
diff --git a/src/panels/config/js/trigger/device.tsx b/src/panels/config/js/trigger/device.tsx
index a9dd929ac1..91d6a8259f 100644
--- a/src/panels/config/js/trigger/device.tsx
+++ b/src/panels/config/js/trigger/device.tsx
@@ -2,7 +2,7 @@ import { h, Component } from "preact";
import "../../../../components/device/ha-device-picker";
import "../../../../components/device/ha-device-trigger-picker";
-import "../../../../components/ha-form";
+import "../../../../components/ha-form/ha-form";
import {
fetchDeviceTriggerCapabilities,
@@ -65,9 +65,9 @@ export default class DeviceTrigger extends Component {
{extraFieldsData && (
)}
@@ -99,15 +99,9 @@ export default class DeviceTrigger extends Component {
}
private _extraFieldsChanged(ev) {
- if (!ev.detail.path) {
- return;
- }
- const item = ev.detail.path.replace("data.", "");
- const value = ev.detail.value || undefined;
-
this.props.onChange(this.props.index, {
...this.props.trigger,
- [item]: value,
+ ...ev.detail.value,
});
}
diff --git a/src/panels/profile/ha-mfa-module-setup-flow.js b/src/panels/profile/ha-mfa-module-setup-flow.js
index df25be0133..79394d8196 100644
--- a/src/panels/profile/ha-mfa-module-setup-flow.js
+++ b/src/panels/profile/ha-mfa-module-setup-flow.js
@@ -5,7 +5,7 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../components/dialog/ha-paper-dialog";
-import "../../components/ha-form";
+import "../../components/ha-form/ha-form";
import "../../components/ha-markdown";
import "../../resources/ha-style";
diff --git a/src/resources/ha-style.ts b/src/resources/ha-style.ts
index c35ab84f64..88b9552598 100644
--- a/src/resources/ha-style.ts
+++ b/src/resources/ha-style.ts
@@ -33,7 +33,9 @@ documentContainer.innerHTML = `
--scrollbar-thumb-color: rgb(194, 194, 194);
- --error-state-color: #db4437;
+
+ --error-color: #db4437;
+ --error-state-color: var(--error-color);
/* states and badges */
--state-icon-color: #44739e;