diff --git a/core/src/components/datetime/datetime.tsx b/core/src/components/datetime/datetime.tsx
index c1200432a0..d5143aea79 100644
--- a/core/src/components/datetime/datetime.tsx
+++ b/core/src/components/datetime/datetime.tsx
@@ -68,6 +68,16 @@ export class Datetime implements ComponentInterface {
private clearFocusVisible?: () => void;
private overlayIsPresenting = false;
+ /**
+ * Whether to highlight the active day with a solid circle (as opposed
+ * to the outline circle around today). If you don't specify an initial
+ * value for the datetime, it doesn't automatically init to a default to
+ * avoid unwanted change events firing. If the solid circle were still
+ * shown then, it would look like a date had already been selected, which
+ * is misleading UX.
+ */
+ private highlightActiveParts = false;
+
private parsedMinuteValues?: number[];
private parsedHourValues?: number[];
private parsedMonthValues?: number[];
@@ -1058,6 +1068,7 @@ export class Datetime implements ComponentInterface {
};
private processValue = (value?: string | null) => {
+ this.highlightActiveParts = !!value;
const valueToProcess = value || getToday();
const { month, day, year, hour, minute, tzOffset } = parseDate(valueToProcess);
@@ -1349,6 +1360,7 @@ export class Datetime implements ComponentInterface {
}
private renderMonth(month: number, year: number) {
+ const { highlightActiveParts } = this;
const yearAllowed = this.parsedYearValues === undefined || this.parsedYearValues.includes(year);
const monthAllowed = this.parsedMonthValues === undefined || this.parsedMonthValues.includes(month);
const isCalMonthDisabled = !yearAllowed || !monthAllowed;
@@ -1424,7 +1436,7 @@ export class Datetime implements ComponentInterface {
class={{
'calendar-day-padding': day === null,
'calendar-day': true,
- 'calendar-day-active': isActive,
+ 'calendar-day-active': isActive && highlightActiveParts,
'calendar-day-today': isToday,
}}
aria-selected={ariaSelected}
@@ -1434,6 +1446,14 @@ export class Datetime implements ComponentInterface {
return;
}
+ /**
+ * Note that for datetimes with confirm/cancel buttons, the value
+ * isn't updated until you call confirm(). We need to bring the
+ * solid circle back on day click for UX reasons, rather than only
+ * show the circle if `value` is truthy.
+ */
+ this.highlightActiveParts = true;
+
this.setWorkingParts({
...this.workingParts,
month,
diff --git a/core/src/components/datetime/test/basic/datetime.e2e.ts b/core/src/components/datetime/test/basic/datetime.e2e.ts
new file mode 100644
index 0000000000..8b2e5efe45
--- /dev/null
+++ b/core/src/components/datetime/test/basic/datetime.e2e.ts
@@ -0,0 +1,30 @@
+import { expect } from '@playwright/test';
+import type { E2EPage } from '@utils/test/playwright';
+import { test } from '@utils/test/playwright';
+
+test.describe('datetime: selecting a day', () => {
+ const testHighlight = async (page: E2EPage, datetimeID: string) => {
+ const today = new Date();
+ await page.goto('/src/components/datetime/test/basic');
+
+ const todayBtn = page.locator(
+ `#${datetimeID} .calendar-day[data-day='${today.getDate()}'][data-month='${today.getMonth() + 1}']`
+ );
+
+ expect(todayBtn).toHaveClass(/calendar-day-today/);
+ expect(todayBtn).not.toHaveClass(/calendar-day-active/);
+
+ await todayBtn.click();
+ await page.waitForChanges();
+
+ expect(todayBtn).toHaveClass(/calendar-day-active/);
+ };
+
+ test('should not highlight a day until one is selected', async ({ page }) => {
+ await testHighlight(page, 'inline-datetime-no-value');
+ });
+
+ test('should not highlight a day until one is selected, with default-buttons', async ({ page }) => {
+ await testHighlight(page, 'custom-datetime');
+ });
+});
diff --git a/core/src/components/datetime/test/basic/index.html b/core/src/components/datetime/test/basic/index.html
index b918590be2..153c85688a 100644
--- a/core/src/components/datetime/test/basic/index.html
+++ b/core/src/components/datetime/test/basic/index.html
@@ -261,6 +261,11 @@