+ // Only show label if it's not a top label and there is a value.
+ const label = this.useTopLabel && this.value ? undefined : this.label;
+
+ return html`
+ ${this.useTopLabel && this.label
+ ? html`
${this.label} `
+ : nothing}
${this.addButtonLabel && !this.value
@@ -180,8 +160,10 @@ export class HaGenericPicker extends LitElement {
@click=${this.open}
@clear=${this._clear}
.icon=${this.icon}
- .showLabel=${this.showLabel}
+ .image=${this.image}
+ .label=${label}
.placeholder=${this.placeholder}
+ .helper=${this.helper}
.value=${this.value}
.valueRenderer=${this.valueRenderer}
.required=${this.required}
@@ -189,6 +171,7 @@ export class HaGenericPicker extends LitElement {
.invalid=${this.invalid}
.hideClearIcon=${this.hideClearIcon}
>
+
`}
@@ -227,8 +210,7 @@ export class HaGenericPicker extends LitElement {
`
: nothing}
- ${this._renderHelper()}
- `;
+ ${this._renderHelper()}`;
}
private _renderComboBox(dialogMode = false) {
@@ -321,7 +303,7 @@ export class HaGenericPicker extends LitElement {
this._newValue = value;
}
- private _clear(e) {
+ private _clear(e: CustomEvent) {
e.stopPropagation();
this._setValue(undefined);
}
diff --git a/src/components/ha-icon-picker.ts b/src/components/ha-icon-picker.ts
index a8fde869f1..f7fcf8a813 100644
--- a/src/components/ha-icon-picker.ts
+++ b/src/components/ha-icon-picker.ts
@@ -113,7 +113,6 @@ export class HaIconPicker extends LitElement {
+
`;
}
diff --git a/src/components/ha-language-picker.ts b/src/components/ha-language-picker.ts
index d7e4d25c9f..4e01181b34 100644
--- a/src/components/ha-language-picker.ts
+++ b/src/components/ha-language-picker.ts
@@ -116,6 +116,11 @@ export class HaLanguagePicker extends LitElement {
> `;
protected render() {
+ const label =
+ this.label ??
+ (this.hass?.localize("ui.components.language-picker.language") ||
+ "Language");
+
const value =
this.value ??
(this.required && !this.disabled ? this._getItems()[0].id : this.value);
@@ -129,10 +134,7 @@ export class HaLanguagePicker extends LitElement {
.emptyLabel=${this.hass?.localize(
"ui.components.language-picker.no_languages"
) || "No languages available"}
- .placeholder=${this.label ??
- (this.hass?.localize("ui.components.language-picker.language") ||
- "Language")}
- show-label
+ .label=${label}
.value=${value}
.valueRenderer=${this._valueRenderer}
.disabled=${this.disabled}
diff --git a/src/components/ha-picker-field.ts b/src/components/ha-picker-field.ts
index 5296863480..cf13ba0ea8 100644
--- a/src/components/ha-picker-field.ts
+++ b/src/components/ha-picker-field.ts
@@ -9,7 +9,9 @@ import {
type TemplateResult,
} from "lit";
import { customElement, property, query, state } from "lit/decorators";
+import { ifDefined } from "lit/directives/if-defined";
import { fireEvent } from "../common/dom/fire_event";
+import { PickerMixin } from "../mixins/picker-mixin";
import { localizeContext } from "../data/context";
import type { HomeAssistant } from "../types";
import "./ha-combo-box-item";
@@ -26,32 +28,7 @@ declare global {
export type PickerValueRenderer = (value: string) => TemplateResult<1>;
@customElement("ha-picker-field")
-export class HaPickerField extends LitElement {
- @property({ type: Boolean }) public disabled = false;
-
- @property({ type: Boolean }) public required = false;
-
- @property() public value?: string;
-
- @property() public icon?: string;
-
- @property() public helper?: string;
-
- @property() public placeholder?: string;
-
- @property({ type: Boolean, reflect: true }) public unknown = false;
-
- @property({ attribute: "unknown-item-text" }) public unknownItemText?: string;
-
- @property({ attribute: "hide-clear-icon", type: Boolean })
- public hideClearIcon = false;
-
- @property({ attribute: "show-label", type: Boolean })
- public showLabel = false;
-
- @property({ attribute: false })
- public valueRenderer?: PickerValueRenderer;
-
+export class HaPickerField extends PickerMixin(LitElement) {
@property({ type: Boolean, reflect: true }) public invalid = false;
@query("ha-combo-box-item", true) public item!: HaComboBoxItem;
@@ -66,15 +43,17 @@ export class HaPickerField extends LitElement {
}
protected render() {
- const hasValue = !!this.value?.length;
+ const hasValue = !!this.value;
const showClearIcon =
!!this.value && !this.required && !this.disabled && !this.hideClearIcon;
+ const placeholderText = this.placeholder ?? this.label;
+
const overlineLabel =
- this.showLabel && hasValue && this.placeholder
+ this.label && hasValue
? html`
${this.placeholder}${this.required ? " *" : ""} ${this.label}${this.required ? " *" : ""}`
: nothing;
@@ -82,17 +61,30 @@ export class HaPickerField extends LitElement {
? this.valueRenderer
? this.valueRenderer(this.value ?? "")
: html`
${this.value} `
- : this.placeholder
+ : placeholderText
? html`
- ${this.placeholder}${this.required ? " *" : ""}
+ ${placeholderText}${this.required ? " *" : ""}
`
: nothing;
return html`
-
- ${this.icon
- ? html` `
- : nothing}
+
+ ${this.image
+ ? html` `
+ : this.icon
+ ? html` `
+ : html` `}
${overlineLabel}${headlineContent}
${this.unknown
? html`
@@ -119,7 +111,7 @@ export class HaPickerField extends LitElement {
`;
}
- private _clear(e) {
+ private _clear(e: CustomEvent) {
e.stopPropagation();
fireEvent(this, "clear");
}
diff --git a/src/components/ha-selector/ha-selector-entity.ts b/src/components/ha-selector/ha-selector-entity.ts
index d05e470a83..7622ba394c 100644
--- a/src/components/ha-selector/ha-selector-entity.ts
+++ b/src/components/ha-selector/ha-selector-entity.ts
@@ -66,12 +66,12 @@ export class HaEntitySelector extends LitElement {
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
+ .placeholder=${this.placeholder}
.helper=${this.helper}
.includeEntities=${this.selector.entity?.include_entities}
.excludeEntities=${this.selector.entity?.exclude_entities}
.entityFilter=${this._filterEntities}
.createDomains=${this._createDomains}
- .placeholder=${this.placeholder}
.disabled=${this.disabled}
.required=${this.required}
allow-custom-entity
@@ -83,13 +83,13 @@ export class HaEntitySelector extends LitElement {
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
+ .placeholder=${this.placeholder}
.helper=${this.helper}
.includeEntities=${this.selector.entity.include_entities}
.excludeEntities=${this.selector.entity.exclude_entities}
.reorder=${this.selector.entity.reorder ?? false}
.entityFilter=${this._filterEntities}
.createDomains=${this._createDomains}
- .placeholder=${this.placeholder}
.disabled=${this.disabled}
.required=${this.required}
>
diff --git a/src/components/ha-selector/ha-selector-icon.ts b/src/components/ha-selector/ha-selector-icon.ts
index c325055911..f31dbc261c 100644
--- a/src/components/ha-selector/ha-selector-icon.ts
+++ b/src/components/ha-selector/ha-selector-icon.ts
@@ -52,7 +52,7 @@ export class HaIconSelector extends LitElement {
${!placeholder && stateObj
? html`
diff --git a/src/components/ha-target-picker.ts b/src/components/ha-target-picker.ts
index 67903b946e..92bebfba9c 100644
--- a/src/components/ha-target-picker.ts
+++ b/src/components/ha-target-picker.ts
@@ -393,6 +393,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
.rowRenderer=${this._renderRow}
.getItems=${this._getItems}
@value-changed=${this._targetPicked}
+ use-top-label
.addButtonLabel=${this.hass.localize(
"ui.components.target-picker.add_target"
)}
diff --git a/src/components/user/ha-user-picker.ts b/src/components/user/ha-user-picker.ts
index 49f6d6205a..ff789e8397 100644
--- a/src/components/user/ha-user-picker.ts
+++ b/src/components/user/ha-user-picker.ts
@@ -132,9 +132,9 @@ class HaUserPicker extends LitElement {
.hass=${this.hass}
.autofocus=${this.autofocus}
.label=${this.label}
- .notFoundLabel=${this._notFoundLabel}
.placeholder=${placeholder}
.value=${this.value}
+ .notFoundLabel=${this._notFoundLabel}
.getItems=${this._getItems}
.valueRenderer=${this._valueRenderer}
.rowRenderer=${this._rowRenderer}
diff --git a/src/mixins/picker-mixin.ts b/src/mixins/picker-mixin.ts
new file mode 100644
index 0000000000..b2e6912576
--- /dev/null
+++ b/src/mixins/picker-mixin.ts
@@ -0,0 +1,38 @@
+import type { ReactiveElement } from "lit";
+import { property } from "lit/decorators";
+import type { Constructor } from "../types";
+import type { PickerValueRenderer } from "../components/ha-picker-field";
+
+export const PickerMixin = >(
+ superClass: T
+) => {
+ class PickerFieldClass extends superClass {
+ @property({ type: Boolean }) public disabled = false;
+
+ @property({ type: Boolean }) public required = false;
+
+ @property() public icon?: string;
+
+ @property() public image?: string;
+
+ @property() public label?: string;
+
+ @property() public placeholder?: string;
+
+ @property() public helper?: string;
+
+ @property() public value?: string;
+
+ @property({ type: Boolean, reflect: true }) public unknown = false;
+
+ @property({ attribute: "unknown-item-text" })
+ public unknownItemText?: string;
+
+ @property({ attribute: "hide-clear-icon", type: Boolean })
+ public hideClearIcon = false;
+
+ @property({ attribute: false })
+ public valueRenderer?: PickerValueRenderer;
+ }
+ return PickerFieldClass;
+};
diff --git a/src/panels/config/areas/dialog-floor-registry-detail.ts b/src/panels/config/areas/dialog-floor-registry-detail.ts
index fa23c3d096..dcb4a5430e 100644
--- a/src/panels/config/areas/dialog-floor-registry-detail.ts
+++ b/src/panels/config/areas/dialog-floor-registry-detail.ts
@@ -160,7 +160,7 @@ class DialogFloorDetail extends LitElement {
${!this._icon
? html`
`
diff --git a/src/panels/config/automation/automation-save-dialog/dialog-automation-save.ts b/src/panels/config/automation/automation-save-dialog/dialog-automation-save.ts
index cd6137dea3..8ed58cacfb 100644
--- a/src/panels/config/automation/automation-save-dialog/dialog-automation-save.ts
+++ b/src/panels/config/automation/automation-save-dialog/dialog-automation-save.ts
@@ -148,7 +148,7 @@ class DialogAutomationSave extends LitElement implements HassDialog {
@value-changed=${this._iconChanged}
>
@@ -176,8 +176,10 @@ class DialogAutomationSave extends LitElement implements HassDialog {
id="category"
.hass=${this.hass}
.scope=${this._params.domain}
+ .label=${this.hass.localize(
+ "ui.components.category-picker.category"
+ )}
.value=${this._entryUpdates.category}
- show-label
@value-changed=${this._registryEntryChanged}
>`
: nothing}
@@ -194,7 +196,6 @@ class DialogAutomationSave extends LitElement implements HassDialog {
id="area"
.hass=${this.hass}
.value=${this._entryUpdates.area}
- show-label
@value-changed=${this._registryEntryChanged}
>`
: nothing}
diff --git a/src/panels/config/category/dialog-assign-category.ts b/src/panels/config/category/dialog-assign-category.ts
index 1243b967ee..b15f38d72b 100644
--- a/src/panels/config/category/dialog-assign-category.ts
+++ b/src/panels/config/category/dialog-assign-category.ts
@@ -65,6 +65,9 @@ class DialogAssignCategory extends LitElement {
diff --git a/src/panels/config/category/ha-category-picker.ts b/src/panels/config/category/ha-category-picker.ts
index 27f7732243..2f91d54390 100644
--- a/src/panels/config/category/ha-category-picker.ts
+++ b/src/panels/config/category/ha-category-picker.ts
@@ -39,9 +39,6 @@ export class HaCategoryPicker extends SubscribeMixin(LitElement) {
@property({ type: Boolean, attribute: "no-add" })
public noAdd = false;
- @property({ type: Boolean, attribute: "show-label" })
- public showLabel = false;
-
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = false;
@@ -183,10 +180,6 @@ export class HaCategoryPicker extends SubscribeMixin(LitElement) {
};
protected render(): TemplateResult {
- const placeholder =
- this.placeholder ??
- this.hass.localize("ui.components.category-picker.category");
-
const valueRenderer = this._computeValueRenderer(this._categories);
return html`
@@ -194,13 +187,12 @@ export class HaCategoryPicker extends SubscribeMixin(LitElement) {
.hass=${this.hass}
.autofocus=${this.autofocus}
.label=${this.label}
+ .placeholder=${this.placeholder}
+ .value=${this.value}
.notFoundLabel=${this._notFoundLabel}
.emptyLabel=${this.hass.localize(
"ui.components.category-picker.no_categories"
)}
- .placeholder=${placeholder}
- .showLabel=${this.showLabel}
- .value=${this.value}
.getItems=${this._getItems}
.getAdditionalItems=${this._getAdditionalItems}
.valueRenderer=${valueRenderer}
diff --git a/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts b/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts
index 7b14b44920..4c350f46c0 100644
--- a/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts
+++ b/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts
@@ -80,7 +80,6 @@ class DialogDeviceRegistryDetail extends LitElement {
@@ -778,7 +778,6 @@ export class EntityRegistrySettingsEditor extends LitElement {
.hass=${this.hass}
.value=${this._areaId}
.disabled=${this.disabled}
- show-label
@value-changed=${this._areaPicked}
>`
: ""}
@@ -1013,7 +1012,6 @@ export class EntityRegistrySettingsEditor extends LitElement {
? html` `