Compare commits

...

1 Commits

Author SHA1 Message Date
Petar Petrov 1135c23905 Stack actions in the recurring calendar event confirmation dialog
Three buttons in a 320px footer row were shrunk to their longest word,
wrapping every word onto its own line and overflowing the button.

Add an opt-in `stacked` mode to ha-dialog-footer that lays the actions out
as full-width buttons, primary action(s) above the secondary one, and use it
in the calendar confirm dialog when the event is recurring.
2026-07-31 13:58:30 +03:00
3 changed files with 78 additions and 5 deletions
+50 -1
View File
@@ -20,7 +20,8 @@ type DialogType =
| "basic-subtitle-below"
| "basic-subtitle-above"
| "form"
| "actions";
| "actions"
| "stacked-footer";
@customElement("demo-components-ha-dialog")
export class DemoHaDialog extends LitElement {
@@ -51,6 +52,9 @@ export class DemoHaDialog extends LitElement {
<ha-button @click=${this._handleOpenDialog("actions")}
>Dialog with actions</ha-button
>
<ha-button @click=${this._handleOpenDialog("stacked-footer")}
>Dialog with stacked footer</ha-button
>
</div>
<ha-dialog
@@ -116,6 +120,42 @@ export class DemoHaDialog extends LitElement {
<div>Dialog content</div>
</ha-dialog>
<ha-dialog
.open=${this._openDialog === "stacked-footer"}
header-title="Delete event"
width="small"
@closed=${this._handleClosed}
>
<div>
Do you want to delete only this event, or this and all future
occurrences of the event?
</div>
<ha-dialog-footer slot="footer" stacked>
<ha-button
slot="secondaryAction"
appearance="plain"
@click=${this._handleClosed}
>
Cancel
</ha-button>
<ha-button
slot="primaryAction"
variant="danger"
@click=${this._handleClosed}
>
Delete only this event
</ha-button>
<ha-button
slot="primaryAction"
variant="danger"
@click=${this._handleClosed}
>
Delete all future events
</ha-button>
</ha-dialog-footer>
</ha-dialog>
<h2>Design</h2>
<h3>Width</h3>
@@ -246,6 +286,15 @@ export class DemoHaDialog extends LitElement {
</tbody>
</table>
<p>
Actions sit side by side on a single line. When the labels are too
long to fit, add the <code>stacked</code> attribute to
<code>ha-dialog-footer</code>: it stacks them as full-width buttons,
with the primary action(s) above the secondary action(s). Without it,
the buttons are squeezed until every word wraps onto its own line. See
the <em>Dialog with stacked footer</em> demo above.
</p>
<h2>Implementation</h2>
<h3>Example Usage</h3>
+24 -3
View File
@@ -1,5 +1,5 @@
import { css, html, LitElement } from "lit";
import { customElement } from "lit/decorators";
import { customElement, property } from "lit/decorators";
/**
* Home Assistant dialog footer component
@@ -14,6 +14,10 @@ import { customElement } from "lit/decorators";
* @slot primaryAction - Primary action button(s), aligned to the end.
* @slot secondaryAction - Secondary action button(s), placed before the primary action.
*
* @attr {boolean} stacked - Stacks the actions as full-width buttons, with the primary
* action(s) above the secondary action(s). Use it when the labels are too long to sit side
* by side, otherwise they are squeezed until every word wraps onto its own line.
*
* @remarks
* **Button Styling Guidance:**
* - `primaryAction` slot: Use `variant="accent"`
@@ -21,11 +25,24 @@ import { customElement } from "lit/decorators";
*/
@customElement("ha-dialog-footer")
export class HaDialogFooter extends LitElement {
@property({ type: Boolean, reflect: true }) public stacked = false;
protected render() {
// Swap the slots rather than reversing with CSS, so that focus and reading
// order keep matching the visual order.
return html`
<footer>
<slot name="secondaryAction"></slot>
<slot name="primaryAction"></slot>
${
this.stacked
? html`
<slot name="primaryAction"></slot>
<slot name="secondaryAction"></slot>
`
: html`
<slot name="secondaryAction"></slot>
<slot name="primaryAction"></slot>
`
}
</footer>
`;
}
@@ -40,6 +57,10 @@ export class HaDialogFooter extends LitElement {
align-items: center;
width: 100%;
}
:host([stacked]) footer {
flex-direction: column;
align-items: stretch;
}
`,
];
}
@@ -49,7 +49,10 @@ class ConfirmEventDialogBox extends LitElement {
<div>
<p>${this._params.text}</p>
</div>
<ha-dialog-footer slot="footer">
<ha-dialog-footer
slot="footer"
?stacked=${!!this._params.confirmFutureText}
>
<ha-button
appearance="plain"
@click=${this._dismiss}