Thanks works!
what do i need to edit to make it show correctly on a smaller screen?
a 10" tablet for example.
A screen shot might help to explain your issue. The configuration includes dynamic sizing based on screen resolution.
Where do I find the dynamic sizing, this is what I want to edit.
Itās in dashboard.yaml.
I thought so but I dont know what to edit, can you point me at instructions or tell me how? please.
Itās this bit:
DAYS: |
(() => {
const width = window.innerWidth;
const calendarView = states['input_select.calendar_view']?.state;
if (width >= 390 && width<= 500) return 1;
if (calendarView === 'Today') return 1;
if (calendarView === 'Tomorrow') return 2;
if (calendarView === 'Bimonth' && width >= 1920) return 56;
if (calendarView === 'Month' && width >= 1920) return 28;
if (calendarView === 'Biweek' && width >= 1920) return 14;
if (calendarView === 'Week' && width >= 1920) return 7;
return 3;
})()
Itās using the resolution width in pixels to decide how many days to display, depending on the chosen view.
I never really tinkered with it and I donāt think there are any instructions on the OPās Github.
Iām actually not using this implementation now. I have swapped to this custom card: Skylight Calendar Card ā A family-friendly schedule card.
Hi @JoeMo22,
Were you able to resolve the āpatternWarningā error. If yes, what was the solution that you used?
Thanks!
Are you both using the Visual Studio Code Server addon (app) to edit your configuration.yaml? If so, you can ignore the pattern warning error.
Otherwise, the entry should look like this:
homeassistant:
packages: !include_dir_named packages
If you donāt have homeassistant:, just create it.
Thanks for replying @Orange-GT3.
I am using the VS Code Server addon.
Forgive an inexperienced user question, but when you say create homeassistant:, what do you mean?
Iāve copy pasted this into config.yaml:
homeassistant:
packages: !include_dir_named packages
Iāve created a packages folder, in the Config folder.
What you have there is correct.
Good, however dashboard.yaml does not go in that folder, family-calendar.yaml does.
You use dashboard.yaml as the basis for a new dashboard to display your calendar.
Hi
Can anyone help me Iām pulling my hair out.
This is my dashboard code but i cannot see the actual weeks planner section.
Iāve tried all sorts but keep getting to a dead end. Iāve even tried gemeni to help me out but no luck
views:
- type: sections
max_columns: 10
title: Family Calendar
path: family-calendar
theme: Skylight
sections:
- type: grid
cards:
- type: custom:better-moment-card
parentStyle: |
line-height:normal;
moment:
- parentStyle: |
font-size:1em; text-align:center; margin-top:5px;
templateRaw: |
{{moment format=cccc}}
- parentStyle: |
font-size:1.5em; text-align:center; margin-top:5px;
templateRaw: |
{{moment format=LLLL dd, yyyy}}
- parentStyle: |
font-size:4em; text-align:center; font-weight:400;
templateRaw: |
{{moment format=HH:mm}}
grid_options:
columns: 20
card_mod:
style: |
ha-card {
background: transparent !important;
box-shadow: none !important;
border: none !important;
}
- type: custom:weather-card
entity: weather.forecast_home
current: true
details: true
forecast: false
grid_options:
columns: 20
rows: 3
- type: weather-forecast
show_current: false
show_forecast: true
entity: weather.forecast_home
forecast_type: daily
name: Weather Forecast
grid_options:
columns: 20
rows: 3
card_mod:
style: |
ha-card {
background: transparent !important;
box-shadow: none !important;
border: none !important;
}
column_span: 10
- type: grid
cards:
- type: vertical-stack
cards:
- type: markdown
content: ' '
card_mod:
style: >
ha-card { background: none; box-shadow: none; border: none;
}
grid_options:
columns: 18
rows: auto
grid_options:
columns: 120
rows: auto
- type: vertical-stack
cards:
- type: markdown
content: <font color="Black" size="6">Family Calendar</font>
grid_options:
columns: 18
rows: auto
grid_options:
columns: 120
rows: auto
- type: horizontal-stack
cards:
- type: custom:bubble-card
card_type: button
button_type: name
entity: calendar.finley
show_icon: true
show_name: true
tap_action:
action: perform-action
perform_action: script.calendar1_calendar_visible_filter
styles: |
.bubble-button-background {
opacity: 1 !important;
background-color: ${hass.states['input_text.calendar1_calendar_filter'].state === '.*' ? 'light-grey' : '#ff7f00'} !important;
}
sub_button:
main: []
bottom: []
slider_fill_orientation: left
slider_value_position: right
name: Finley
- type: custom:bubble-card
card_type: button
button_type: name
entity: calendar.winnie
show_icon: true
show_name: true
tap_action:
action: perform-action
perform_action: script.calendar2_calendar_visible_filter
styles: |
.bubble-button-background {
opacity: 1 !important;
background-color: ${hass.states['input_text.calendar2_calendar_filter'].state === '.*' ? 'light-grey' : '#ff7f00'} !important;
}
sub_button:
main: []
bottom: []
slider_fill_orientation: left
slider_value_position: right
name: Winnie
- type: custom:bubble-card
card_type: button
button_type: name
entity: calendar.jodi
show_icon: true
show_name: true
tap_action:
action: perform-action
perform_action: script.calendar3_calendar_visible_filter
target: {}
styles: |
.bubble-button-background {
opacity: 1 !important;
background-color: ${hass.states['input_text.calendar4_calendar_filter'].state === '.*' ? 'light-grey' : 'var(--calendar4-default-primary-color)'} !important;
}
sub_button:
main: []
bottom: []
slider_fill_orientation: left
slider_value_position: right
name: Jodi
- type: custom:bubble-card
card_type: button
button_type: name
entity: calendar.tom
show_icon: true
show_name: true
tap_action:
action: perform-action
perform_action: script.calendar4_calendar_visible_filter
styles: |
.bubble-button-background {
opacity: 1 !important;
background-color: ${hass.states['input_text.calendar4_calendar_filter'].state === '.*' ? 'light-grey' : 'var(--calendar4-default-primary-color)'} !important;
}
sub_button:
main: []
bottom: []
slider_fill_orientation: left
slider_value_position: right
name: Tom
- type: custom:bubble-card
card_type: button
button_type: switch
name: Family
icon: mdi:human-male-female-child
show_icon: true
show_name: true
tap_action:
action: perform-action
perform_action: script.family_calendar_visible_filter
styles: |
.bubble-button-background {
opacity: 1 !important;
background-color: ${hass.states['input_text.family_calendar_filter'].state === '.*' ? 'light-grey' : '#4A90E2'} !important;
}
entity: input_boolean.family_calendar_show
- type: custom:bubble-card
card_type: button
button_type: name
name: Birthdays
icon: mdi:cake-variant
show_icon: true
show_name: true
tap_action:
action: perform-action
perform_action: script.birthdays_calendar_visible_filter
styles: |
.bubble-button-background {
opacity: 1 !important;
background-color: ${hass.states['input_text.birthdays_calendar_filter'].state === '.*' ? 'light-grey' : '#33a02c'} !important;
}
- type: custom:bubble-card
card_type: button
button_type: name
name: Holidays
icon: mdi:bag-personal
show_icon: true
show_name: true
tap_action:
action: perform-action
perform_action: script.holidays_calendar_visible_filter
styles: |
.bubble-button-background {
opacity: 1 !important;
background-color: ${hass.states['input_text.holidays_calendar_filter'].state === '.*' ? 'light-grey' : '#ff7f00'} !important;
}
sub_button:
main: []
bottom: []
slider_fill_orientation: left
slider_value_position: right
grid_options:
columns: 45
rows: auto
- type: markdown
content: ' '
grid_options:
columns: 3
rows: auto
- type: custom:bubble-card
card_type: button
button_type: name
card_layout: large
name: Add Event
icon: mdi:calendar-plus
tap_action:
action: navigate
navigation_path: '#addcalendarevent'
styles: >
* { font-size: 1.05em !important; }
ha-card { --bubble-main-background-color: #393745 !important;
width: 300px; }
.bubble-icon { --mdc-icon-size: 30px !important; color: snow
!important; opacity: 1; }
.bubble-icon-container { background: #393745 !important; display:
flex; }
.bubble-name { color: snow !important; opacity: 1; display: flex;
line-height: 18px; flex-direction: row; justify-content: center;
flex-grow: 1; margin: 0 40px 0 0; pointer-events: none; position:
relative; overflow: hidden; }
grid_options:
columns: 10
rows: 1
- type: custom:bubble-card
card_type: select
entity: input_select.calendar_view
show_name: true
show_state: true
name: Select View
show_last_changed: false
show_attribute: false
column_span: 10
- type: grid
cards:
- type: custom:config-template-card
entities:
- input_text.calendar1_calendar_filter
- input_text.calendar2_calendar_filter
- input_text.calendar3_calendar_filter
- input_text.calendar4_calendar_filter
- input_text.family_calendar_filter
- input_text.holidays_calendar_filter
- input_text.birthdays_calendar_filter
- input_select.calendar_view
variables:
CAL1CAL: states['input_text.calendar1_calendar_filter']?.state
CAL2CAL: states['input_text.calendar2_calendar_filter']?.state
CAL3CAL: states['input_text.calendar3_calendar_filter']?.state
CAL4CAL: states['input_text.calendar4_calendar_filter']?.state
FAMCAL: states['input_text.family_calendar_filter']?.state
HOLCAL: states['input_text.holidays_calendar_filter']?.state
BIRCAL: states['input_text.birthdays_calendar_filter']?.state
VIEW: states['input_select.calendar_view']?.state
STARTDAY: |
(() => {
const calendarView = states['input_select.calendar_view']?.state;
if (calendarView === 'Today') return 'today';
if (calendarView === 'Tomorrow') return 'tomorrow';
// Fallback
return 'monday'; # <--- UPDATE THIS IF NEEDED, valid values are: monday, tuesday, wednesday, thursday, friday, saturday, sunday
})()
DAYS: |
(() => {
const calendarView = states['input_select.calendar_view']?.state;
if (calendarView === 'Today') return 1;
if (calendarView === 'Tomorrow') return 2;
if (calendarView === 'Week') return 7;
if (calendarView === 'Biweek') return 14;
// else return "month"
return "month";
})()
card:
type: custom:week-planner-card
calendars:
- entity: calendar.calendar1
name: calendar1
color: var(--calendar1-default-primary-color)
filter: ${ CAL1CAL }
- entity: calendar.calendar2
name: calendar2
color: var(--calendar2-default-primary-color)
filter: ${ CAL2CAL }
- entity: calendar.calendar3
name: calendar3
color: var(--calendar3-default-primary-color)
filter: ${ CAL3CAL }
- entity: calendar.calendar4
name: calendar4
color: var(--calendar4-default-primary-color)
filter: ${ CAL4CAL }
- entity: calendar.family
name: Family
color: var(--family-default-primary-color)
filter: ${ FAMCAL }
- entity: calendar.birthdays
name: Birthdays
color: var(--birthdays-default-primary-color)
filter: ${ BIRCAL }
- entity: calendar.holidays
name: Holidays
color: var(--holidays-default-primary-color)
filter: ${ HOLCAL }
days: ${ DAYS }
startingDay: ${ STARTDAY }
showNavigation: true
showWeekDayText: false
startingDayOffset: 0
hideWeekend: false
noCardBackground: false
compact: false
weather:
showCondition: true
showTemperature: true
showLowTemperature: true
useTwiceDaily: false
entity: weather.home
locale: en
showLocation: true
hidePastEvents: false
hideDaysWithoutEvents: false
hideTodayWithoutEvents: false
combineSimilarEvents: true
showLegend: false
legendToggle: false
card_mod:
style: >
/* === BASE SAFETY === */
:host {
overflow: hidden;
}
/* === CARD BASE === */
ha-card {
background: rgba(255, 255, 255, 0.6) !important;
border-radius: 24px !important;
box-shadow: none !important;
height: clamp(480px, 70vh, 900px) !important;
max-height: clamp(480px, 70vh, 900px) !important;
}
/* === GRID LAYOUT === */
.container {
display: grid !important;
grid-template-columns: repeat(7, minmax(0, 1fr)) !important;
grid-auto-flow: row dense !important;
gap: 0 !important;
}
.container .navigation,
.container .header {
grid-column: 1 / -1 !important;
}
/* WEEKDAY LABEL CELLS */
.day.header {
display: block !important;
grid-column: auto !important;
margin: 0 !important;
padding: 0.2em !important;
text-align: center !important;
box-sizing: border-box !important;
}
.day.header .date .text {
font-weight: 600 !important;
}
/* === DAY TILES === */
.day {
border: solid 1px whitesmoke !important;
padding: 0.2% !important;
width: auto !important;
min-width: 0 !important;
margin: 0 !important;
box-sizing: border-box !important;
align-self: stretch !important;
justify-self: stretch !important;
}
/* === YOUR ORIGINAL VISUAL RULES === */
.event.past {
opacity: .2 !important;
background-color: gray !important;
}
.time {
color: #333333 !important;
font-size: 0.8em !important;
}
.event {
color: #333333 !important;
line-height: 16px !important;
background-color: var(--border-color) !important;
border-radius: 10px !important;
max-height: 80px !important;
overflow: hidden !important;
font-size: 1.1em !important;
}
.none {
background-color: transparent !important;
}
.today .number {
border-radius: 5px !important;
background-color: orange !important;
padding-left: 4px !important;
padding-right: 4px !important;
}
.day .date .text {
font-size: 1em !important;
font-weight: bold !important;
}
.day .date .number {
font-weight: bold !important;
font-size: 3em !important;
}
/* Weekday colors */
/* When showWeekDayText is true */
.day[data-weekday="1"] .date .text,
.day[data-weekday="2"] .date .text,
.day[data-weekday="3"] .date .text,
.day[data-weekday="4"] .date .text,
.day[data-weekday="5"] .date .text {
color: #2e7d32 !important;
}
.day[data-weekday="6"] .date .text,
.day[data-weekday="7"] .date .text {
color: #d32f2f !important;
}
/* When showWeekDayText is false */
.container > .day.header .text {
color: #2e7d32 !important;
}
/* Saturday = column 7 */
.container > .day.header:nth-of-type(7) .text {
color: #d32f2f !important;
}
/* Sunday = column 8 */
.container > .day.header:nth-of-type(8) .text {
color: #d32f2f !important;
}
/* === RESPONSIVE BREAKPOINTS === */
@media (max-width: 1024px) {
.day .date .number { font-size: 2em !important; }
.day .date .text { font-size: 0.95em !important; }
}
@media (max-width: 768px) {
.day .date .number { font-size: 1.6em !important; }
.day .date .text { font-size: 0.85em !important; }
.event { font-size: 0.85em !important; line-height: 1.1em !important; }
.time { font-size: 0.75em !important; }
}
/* =========================================================
*/
/* === MOBILE OVERLAP FIX + TWOāLINE WRAP FOR TITLES ========
*/
/* =========================================================
*/
@media (max-width: 480px) {
:host {
font-size: clamp(10px, 2.6vw, 13px) !important;
}
/* Condensed headers */
.container .header,
.container .navigation {
padding: 0.25em 0.4em !important;
}
/* Day tiles tighter */
.day {
padding: 0.15em !important;
min-width: 0 !important;
}
/* Smaller date numbers */
.day .date .number {
font-size: clamp(1.1em, 4.5vw, 1.4em) !important;
line-height: 1.1 !important;
}
.day .date .text {
font-size: clamp(0.72em, 3.2vw, 0.85em) !important;
line-height: 1.1 !important;
}
/* Event chip reduced */
.event {
font-size: clamp(0.72em, 2.9vw, 0.85em) !important;
line-height: 1.05em !important;
padding: 0.25em 0.35em !important;
max-height: 62px !important;
}
.time {
font-size: clamp(0.65em, 2.5vw, 0.78em) !important;
}
/* === TWO-LINE WRAP FOR TITLES === */
.event .title,
.event .name,
.event .summary,
.event .location,
.event .desc,
.event .description {
display: -webkit-box !important;
-webkit-box-orient: vertical !important;
-webkit-line-clamp: 2 !important; /* <<< Two lines max */
overflow: auto !important;
text-overflow: ellipsis !important;
white-space: normal !important;
line-height: 1.1em !important;
max-height: calc(1.1em * 2) !important;
}
}
/* Slightly larger phones / small tablets */
@media (min-width: 481px) and (max-width: 768px) {
:host {
font-size: clamp(11px, 2.2vw, 14px) !important;
}
.event {
max-height: 72px !important;
}
.event .title,
.event .name,
.event .summary {
display: -webkit-box !important;
-webkit-line-clamp: 2 !important;
overflow: auto !important;
}
}
grid_options:
columns: 120
rows: 1
showDescription: false
column_span: 10
- type: grid
cards:
- type: vertical-stack
cards:
- type: custom:bubble-card
card_type: pop-up
hash: '#addcalendarevent'
button_type: name
name: Add Calendar Event
icon: mdi:calendar-plus
show_icon: true
show_name: true
styles: |
.bubble-button-card-container {
background:
${hass.states['input_select.calendar_select'].state == 'calendar1' ? 'var(--calendar1-default-primary-color)'
: hass.states['input_select.calendar_select'].state == 'calendar2' ? 'var(--calendar2-default-primary-color)'
: hass.states['input_select.calendar_select'].state == 'calendar3' ? 'var(--calendar3-default-primary-color)'
: hass.states['input_select.calendar_select'].state == 'calendar4' ? 'var(--calendar4-default-primary-color)'
: hass.states['input_select.calendar_select'].state == 'Family' ? 'var(--family-default-primary-color)'
: 'gray'} !important;
}
- type: vertical-stack
cards:
- type: entities
entities:
- entity: input_select.calendar_select
- entity: input_text.calendar_event_title
name: Event Title
- entity: input_text.calendar_event_description
name: Event Description
- entity: input_boolean.calendar_all_day_event
name: All Day Event
title: Add Calendar Event
state_color: false
- type: conditional
conditions:
- entity: input_boolean.calendar_all_day_event
state: 'off'
card:
type: entities
entities:
- entity: input_datetime.calendar_event_start
name: Start Time
- entity: input_datetime.calendar_event_end
name: End Time
- type: conditional
conditions:
- entity: input_boolean.calendar_all_day_event
state: 'on'
card:
type: entities
entities:
- entity: input_datetime.calendar_day_event_start
name: Event Start Date
- entity: input_datetime.calendar_day_event_end
name: Event End Date
- type: custom:button-card
name: Add Event to Calendar
tap_action:
action: call-service
service: script.add_google_calendar_event
styles:
card:
- background-color: |
[[[
if (states['input_select.calendar_select'].state == 'calendar1') return "var(--calendar1-default-primary-color)";
if (states['input_select.calendar_select'].state == 'calendar2') return "var(--calendar2-default-primary-color)";
if (states['input_select.calendar_select'].state == 'calendar3') return "var(--calendar3-default-primary-color)";
if (states['input_select.calendar_select'].state == 'calendar4') return "var(--calendar4-default-primary-color)";
if (states['input_select.calendar_select'].state == 'Family') return "var(--family-default-primary-color)";
return "gray";
]]]
cards: []
icon: mdi:calendar-blank-multiple
background:
opacity: 62
alignment: center
size: cover
repeat: repeat
attachment: fixed
top_margin: false
This is what I see
Im just trying to get everything fixed before i worry about sizing and themes
THanks
Replace this line
return 'monday'; # <--- UPDATE THIS IF NEEDED, valid values are: monday, tuesday, wednesday, thursday, friday, saturday, sunday
with this and it will start working
return 'monday'; // <--- UPDATE THIS IF NEEDED, valid values are: monday, tuesday, wednesday, thursday, friday, saturday, sunday
Check that you updated the weather entity in dashboard.yaml.
There is an alternative to this that is much easier to configure.
Iām confused what you mean as all my weather cards are working ok
There is a weather entity in the calendar card config that you need to update.
HA is throwing an error anytime I try to add an all-day event that is a single day
Error is āFailed to perform the action script/add_google_calendar_event. Expected minimum event duration of 0:00:01 (2026-02-21, 2026-02-21)ā
Itās odd because the error is referencing a Google Calendar event, but I am trying to add this to a local calendar.
Any guidance on a resolution for this?
Never mind. I just solved this myself. Itās because of ICS-Calendar-Tools, where you have to set the end date of the event as the next day. So if I want an all day on 2/21, I set start for 2/21 and end for 2/22, and then it shows the all day for just 2/21ā¦
Hi Mate,
First of all - such an amazing job.
After many problems i finally got it working ![]()
Just wanted to ask - howās it going with chores? ![]()
Could You share the code for it?
Greetings from Poland ![]()


