diff --git a/gallery/src/pages/components/ha-selector.ts b/gallery/src/pages/components/ha-selector.ts
index 15482b68d0..972c7d7f26 100644
--- a/gallery/src/pages/components/ha-selector.ts
+++ b/gallery/src/pages/components/ha-selector.ts
@@ -261,6 +261,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
@state() private _required = false;
+ @state() private _helper = false;
+
@state() private _label = true;
private data = SCHEMAS.map(() => ({}));
@@ -418,6 +420,13 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
@change=${this._handleOptionChange}
>
+
+
+
${SCHEMAS.map((info, idx) => {
const data = this.data[idx];
@@ -446,6 +455,7 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
.disabled=${this._disabled}
.required=${this._required}
@value-changed=${valueChanged}
+ .helper=${this._helper ? "Helper text" : undefined}
>
`
@@ -466,7 +476,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
width: 60;
}
.options {
- padding: 16px 48px;
+ max-width: 800px;
+ margin: 16px auto;
}
.options ha-formfield {
margin-right: 16px;
diff --git a/src/components/device/ha-device-picker.ts b/src/components/device/ha-device-picker.ts
index ea62482637..9ff64d812f 100644
--- a/src/components/device/ha-device-picker.ts
+++ b/src/components/device/ha-device-picker.ts
@@ -52,6 +52,8 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
@property() public value?: string;
+ @property() public helper?: string;
+
@property() public devices?: DeviceRegistryEntry[];
@property() public areas?: AreaRegistryEntry[];
@@ -269,6 +271,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
? this.hass.localize("ui.components.device-picker.device")
: this.label}
.value=${this._value}
+ .helper=${this.helper}
.renderer=${rowRenderer}
.disabled=${this.disabled}
.required=${this.required}
diff --git a/src/components/device/ha-devices-picker.ts b/src/components/device/ha-devices-picker.ts
index 5b2e0245b9..688467c2a8 100644
--- a/src/components/device/ha-devices-picker.ts
+++ b/src/components/device/ha-devices-picker.ts
@@ -11,6 +11,8 @@ class HaDevicesPicker extends LitElement {
@property() public value?: string[];
+ @property() public helper?: string;
+
@property({ type: Boolean }) public required?: boolean;
/**
@@ -64,6 +66,7 @@ class HaDevicesPicker extends LitElement {
diff --git a/src/components/entity/ha-entity-attribute-picker.ts b/src/components/entity/ha-entity-attribute-picker.ts
index 49bfd1db33..3a73ad3fcb 100644
--- a/src/components/entity/ha-entity-attribute-picker.ts
+++ b/src/components/entity/ha-entity-attribute-picker.ts
@@ -28,6 +28,8 @@ class HaEntityAttributePicker extends LitElement {
@property() public value?: string;
+ @property() public helper?: string;
+
@property({ type: Boolean }) private _opened = false;
@query("ha-combo-box", true) private _comboBox!: HaComboBox;
@@ -64,6 +66,7 @@ class HaEntityAttributePicker extends LitElement {
)}
.disabled=${this.disabled || !this.entityId}
.required=${this.required}
+ .helper=${this.helper}
.allowCustomValue=${this.allowCustomValue}
item-value-path="value"
item-label-path="label"
diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts
index c8f288ad70..7f9c8d3d80 100644
--- a/src/components/entity/ha-entity-picker.ts
+++ b/src/components/entity/ha-entity-picker.ts
@@ -48,6 +48,8 @@ export class HaEntityPicker extends LitElement {
@property() public value?: string;
+ @property() public helper?: string;
+
/**
* Show entities from specific domains.
* @type {Array}
@@ -304,6 +306,7 @@ export class HaEntityPicker extends LitElement {
.label=${this.label === undefined
? this.hass.localize("ui.components.entity.entity-picker.entity")
: this.label}
+ .helper=${this.helper}
.allowCustomValue=${this.allowCustomEntity}
.filteredItems=${this._states}
.renderer=${rowRenderer}
diff --git a/src/components/ha-addon-picker.ts b/src/components/ha-addon-picker.ts
index 7a7abf13b1..d2b413cace 100644
--- a/src/components/ha-addon-picker.ts
+++ b/src/components/ha-addon-picker.ts
@@ -29,6 +29,8 @@ class HaAddonPicker extends LitElement {
@property() public value = "";
+ @property() public helper?: string;
+
@state() private _addons?: HassioAddonInfo[];
@property({ type: Boolean }) public disabled = false;
@@ -62,6 +64,7 @@ class HaAddonPicker extends LitElement {
.value=${this._value}
.required=${this.required}
.disabled=${this.disabled}
+ .helper=${this.helper}
.renderer=${rowRenderer}
.items=${this._addons}
item-value-path="slug"
diff --git a/src/components/ha-area-picker.ts b/src/components/ha-area-picker.ts
index b841575b67..2192bd931c 100644
--- a/src/components/ha-area-picker.ts
+++ b/src/components/ha-area-picker.ts
@@ -49,6 +49,8 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
@property() public value?: string;
+ @property() public helper?: string;
+
@property() public placeholder?: string;
@property({ type: Boolean, attribute: "no-add" })
@@ -312,6 +314,7 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
return html`
PM
`}
- ${this.helper ? html`${this.helper}
` : ""}
+ ${this.helper
+ ? html`${this.helper}`
+ : ""}
`;
}
@@ -350,13 +353,6 @@ export class HaBaseTimeInput extends LitElement {
color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));
padding-left: 4px;
}
-
- .helper {
- color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6));
- font-size: 0.75rem;
- padding-left: 16px;
- padding-right: 16px;
- }
`;
}
diff --git a/src/components/ha-combo-box.ts b/src/components/ha-combo-box.ts
index c1bc266ed9..c0166ddfa8 100644
--- a/src/components/ha-combo-box.ts
+++ b/src/components/ha-combo-box.ts
@@ -64,6 +64,8 @@ export class HaComboBox extends LitElement {
@property() public validationMessage?: string;
+ @property() public helper?: string;
+
@property({ attribute: "error-message" }) public errorMessage?: string;
@property({ type: Boolean }) public invalid?: boolean;
@@ -147,6 +149,8 @@ export class HaComboBox extends LitElement {
.suffix=${html``}
.icon=${this.icon}
.invalid=${this.invalid}
+ .helper=${this.helper}
+ helperPersistent
>
diff --git a/src/components/ha-date-input.ts b/src/components/ha-date-input.ts
index 0963b1fd02..c776519ceb 100644
--- a/src/components/ha-date-input.ts
+++ b/src/components/ha-date-input.ts
@@ -39,11 +39,15 @@ export class HaDateInput extends LitElement {
@property() public label?: string;
+ @property() public helper?: string;
+
render() {
return html``;
+ }
+
+ static styles = css`
+ :host {
+ display: block;
+ color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6));
+ font-size: 0.75rem;
+ padding-left: 16px;
+ padding-right: 16px;
+ }
+ `;
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-input-helper-text": InputHelperText;
+ }
+}
diff --git a/src/components/ha-labeled-slider.js b/src/components/ha-labeled-slider.js
index af7134ab13..00d1b1848f 100644
--- a/src/components/ha-labeled-slider.js
+++ b/src/components/ha-labeled-slider.js
@@ -46,6 +46,9 @@ class HaLabeledSlider extends PolymerElement {
value="{{value}}"
>
+
+ [[helper]]
+
`;
}
@@ -62,6 +65,7 @@ class HaLabeledSlider extends PolymerElement {
max: Number,
pin: Boolean,
step: Number,
+ helper: String,
extra: {
type: Boolean,
diff --git a/src/components/ha-selector/ha-selector-addon.ts b/src/components/ha-selector/ha-selector-addon.ts
index acabb24cf5..91aee42777 100644
--- a/src/components/ha-selector/ha-selector-addon.ts
+++ b/src/components/ha-selector/ha-selector-addon.ts
@@ -14,6 +14,8 @@ export class HaAddonSelector extends LitElement {
@property() public label?: string;
+ @property() public helper?: string;
+
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -23,6 +25,7 @@ export class HaAddonSelector extends LitElement {
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
+ .helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
allow-custom-entity
diff --git a/src/components/ha-selector/ha-selector-area.ts b/src/components/ha-selector/ha-selector-area.ts
index 8aaada7e23..f922d8d0c6 100644
--- a/src/components/ha-selector/ha-selector-area.ts
+++ b/src/components/ha-selector/ha-selector-area.ts
@@ -18,6 +18,8 @@ export class HaAreaSelector extends LitElement {
@property() public label?: string;
+ @property() public helper?: string;
+
@state() public _configEntries?: ConfigEntry[];
@property({ type: Boolean }) public disabled = false;
@@ -47,6 +49,7 @@ export class HaAreaSelector extends LitElement {
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
+ .helper=${this.helper}
no-add
.deviceFilter=${this._filterDevices}
.entityFilter=${this._filterEntities}
@@ -66,6 +69,7 @@ export class HaAreaSelector extends LitElement {
-
- `;
+ return html`
+
+
+
+ ${this.helper
+ ? html`${this.helper}`
+ : ""}
+ `;
}
private _handleChange(ev) {
@@ -35,12 +43,10 @@ export class HaBooleanSelector extends LitElement {
static get styles(): CSSResultGroup {
return css`
- :host {
- height: 56px;
- display: flex;
- }
ha-formfield {
- width: 100%;
+ display: flex;
+ height: 56px;
+ align-items: center;
--mdc-typography-body2-font-size: 1em;
}
`;
diff --git a/src/components/ha-selector/ha-selector-color-rgb.ts b/src/components/ha-selector/ha-selector-color-rgb.ts
index 780d83c832..8597fa783e 100644
--- a/src/components/ha-selector/ha-selector-color-rgb.ts
+++ b/src/components/ha-selector/ha-selector-color-rgb.ts
@@ -16,6 +16,8 @@ export class HaColorRGBSelector extends LitElement {
@property() public label?: string;
+ @property() public helper?: string;
+
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -24,9 +26,11 @@ export class HaColorRGBSelector extends LitElement {
return html`
diff --git a/src/components/ha-selector/ha-selector-color-temp.ts b/src/components/ha-selector/ha-selector-color-temp.ts
index 67ac8abcc7..c3cbb5ffe8 100644
--- a/src/components/ha-selector/ha-selector-color-temp.ts
+++ b/src/components/ha-selector/ha-selector-color-temp.ts
@@ -15,6 +15,8 @@ export class HaColorTempSelector extends LitElement {
@property() public label?: string;
+ @property() public helper?: string;
+
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -29,6 +31,7 @@ export class HaColorTempSelector extends LitElement {
.max=${this.selector.color_temp.max_mireds ?? 500}
.value=${this.value}
.disabled=${this.disabled}
+ .helper=${this.helper}
.required=${this.required}
@change=${this._valueChanged}
>
diff --git a/src/components/ha-selector/ha-selector-date.ts b/src/components/ha-selector/ha-selector-date.ts
index 47fa5b7d91..cfde72537e 100644
--- a/src/components/ha-selector/ha-selector-date.ts
+++ b/src/components/ha-selector/ha-selector-date.ts
@@ -14,6 +14,8 @@ export class HaDateSelector extends LitElement {
@property() public label?: string;
+ @property() public helper?: string;
+
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -26,6 +28,7 @@ export class HaDateSelector extends LitElement {
.disabled=${this.disabled}
.value=${this.value}
.required=${this.required}
+ .helper=${this.helper}
>
`;
diff --git a/src/components/ha-selector/ha-selector-datetime.ts b/src/components/ha-selector/ha-selector-datetime.ts
index c8d1dab2d3..cdb15ccacc 100644
--- a/src/components/ha-selector/ha-selector-datetime.ts
+++ b/src/components/ha-selector/ha-selector-datetime.ts
@@ -6,6 +6,7 @@ import type { HomeAssistant } from "../../types";
import "../ha-date-input";
import type { HaDateInput } from "../ha-date-input";
import "../ha-time-input";
+import "../ha-input-helper-text";
import type { HaTimeInput } from "../ha-time-input";
@customElement("ha-selector-datetime")
@@ -18,6 +19,8 @@ export class HaDateTimeSelector extends LitElement {
@property() public label?: string;
+ @property() public helper?: string;
+
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -30,23 +33,28 @@ export class HaDateTimeSelector extends LitElement {
const values = this.value?.split(" ");
return html`
-
-
-
+
+
+
+
+
+ ${this.helper
+ ? html`${this.helper}`
+ : ""}
`;
}
@@ -58,7 +66,7 @@ export class HaDateTimeSelector extends LitElement {
}
static styles = css`
- :host {
+ .input {
display: flex;
align-items: center;
flex-direction: row;
diff --git a/src/components/ha-selector/ha-selector-device.ts b/src/components/ha-selector/ha-selector-device.ts
index efb5dee013..b6358bf284 100644
--- a/src/components/ha-selector/ha-selector-device.ts
+++ b/src/components/ha-selector/ha-selector-device.ts
@@ -17,6 +17,8 @@ export class HaDeviceSelector extends LitElement {
@property() public label?: string;
+ @property() public helper?: string;
+
@state() public _configEntries?: ConfigEntry[];
@property({ type: Boolean }) public disabled = false;
@@ -43,6 +45,7 @@ export class HaDeviceSelector extends LitElement {
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
+ .helper=${this.helper}
.deviceFilter=${this._filterDevices}
.includeDeviceClasses=${this.selector.device.entity?.device_class
? [this.selector.device.entity.device_class]
@@ -62,6 +65,7 @@ export class HaDeviceSelector extends LitElement {
+ ${!isBox
+ ? html`
`
+ : ""}
+
+
+
+ ${!isBox && this.helper
+ ? html`${this.helper}`
: ""}
-
- `;
+ `;
}
private get _value() {
@@ -92,7 +103,7 @@ export class HaNumberSelector extends LitElement {
static get styles(): CSSResultGroup {
return css`
- :host {
+ .input {
display: flex;
justify-content: space-between;
align-items: center;
diff --git a/src/components/ha-selector/ha-selector-select.ts b/src/components/ha-selector/ha-selector-select.ts
index 2f79979e90..85eaefd610 100644
--- a/src/components/ha-selector/ha-selector-select.ts
+++ b/src/components/ha-selector/ha-selector-select.ts
@@ -58,6 +58,7 @@ export class HaSelectSelector extends LitElement {
`
)}
+ ${this._renderHelper()}
`;
}
@@ -76,6 +77,7 @@ export class HaSelectSelector extends LitElement {
`
)}
+ ${this._renderHelper()}
`;
}
@@ -107,6 +109,7 @@ export class HaSelectSelector extends LitElement {
item-label-path="label"
.hass=${this.hass}
.label=${this.label}
+ .helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required && !value.length}
.value=${this._filter}
@@ -131,6 +134,7 @@ export class HaSelectSelector extends LitElement {
item-label-path="label"
.hass=${this.hass}
.label=${this.label}
+ .helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
.items=${options}
@@ -161,6 +165,12 @@ export class HaSelectSelector extends LitElement {
`;
}
+ private _renderHelper() {
+ return this.helper
+ ? html`${this.helper}`
+ : "";
+ }
+
private get _mode(): "list" | "dropdown" {
return (
this.selector.select.mode ||
diff --git a/src/components/ha-selector/ha-selector-target.ts b/src/components/ha-selector/ha-selector-target.ts
index cf25317cce..4720598a77 100644
--- a/src/components/ha-selector/ha-selector-target.ts
+++ b/src/components/ha-selector/ha-selector-target.ts
@@ -26,6 +26,8 @@ export class HaTargetSelector extends SubscribeMixin(LitElement) {
@property() public label?: string;
+ @property() public helper?: string;
+
@state() private _entityPlaformLookup?: Record;
@state() private _configEntries?: ConfigEntry[];
@@ -64,6 +66,7 @@ export class HaTargetSelector extends SubscribeMixin(LitElement) {
return html`
diff --git a/src/components/ha-target-picker.ts b/src/components/ha-target-picker.ts
index 85fb984a59..b1182779bb 100644
--- a/src/components/ha-target-picker.ts
+++ b/src/components/ha-target-picker.ts
@@ -43,6 +43,7 @@ import type { HaEntityPickerEntityFilterFunc } from "./entity/ha-entity-picker";
import "./ha-area-picker";
import "./ha-icon-button";
import "./ha-svg-icon";
+import "./ha-input-helper-text";
@customElement("ha-target-picker")
export class HaTargetPicker extends SubscribeMixin(LitElement) {
@@ -52,6 +53,8 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
@property() public label?: string;
+ @property() public helper?: string;
+
/**
* Show only targets with entities from specific domains.
* @type {Array}
@@ -213,7 +216,11 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
- `;
+
+
+ ${this.helper
+ ? html`${this.helper}`
+ : ""} `;
}
private async _showPicker(ev) {
diff --git a/src/components/ha-time-input.ts b/src/components/ha-time-input.ts
index 2bf5659841..eadbc744ce 100644
--- a/src/components/ha-time-input.ts
+++ b/src/components/ha-time-input.ts
@@ -14,6 +14,8 @@ export class HaTimeInput extends LitElement {
@property() public label?: string;
+ @property() public helper?: string;
+
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = false;
@@ -46,6 +48,7 @@ export class HaTimeInput extends LitElement {
@value-changed=${this._timeChanged}
.enableSecond=${this.enableSecond}
.required=${this.required}
+ .helper=${this.helper}
>
`;
}
diff --git a/src/components/map/ha-locations-editor.ts b/src/components/map/ha-locations-editor.ts
index d21a7185ac..2dcc446099 100644
--- a/src/components/map/ha-locations-editor.ts
+++ b/src/components/map/ha-locations-editor.ts
@@ -21,6 +21,7 @@ import type { LeafletModuleType } from "../../common/dom/setup-leaflet-map";
import type { HomeAssistant } from "../../types";
import "./ha-map";
import type { HaMap } from "./ha-map";
+import "../ha-input-helper-text";
declare global {
// for fire event
@@ -50,6 +51,8 @@ export class HaLocationsEditor extends LitElement {
@property({ attribute: false }) public locations?: MarkerLocation[];
+ @property() public helper?: string;
+
@property({ type: Boolean }) public autoFit = false;
@property({ type: Number }) public zoom = 16;
@@ -102,13 +105,18 @@ export class HaLocationsEditor extends LitElement {
}
protected render(): TemplateResult {
- return html``;
+ return html`
+
+ ${this.helper
+ ? html`${this.helper}`
+ : ""}
+ `;
}
private _getLayers = memoizeOne(
@@ -287,13 +295,10 @@ export class HaLocationsEditor extends LitElement {
static get styles(): CSSResultGroup {
return css`
- :host {
+ ha-map {
display: block;
height: 300px;
}
- ha-map {
- height: 100%;
- }
`;
}
}