> ## Documentation Index
> Fetch the complete documentation index at: https://docs.daylightcalendar.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Event Styles: Custom Colors and Icons for Calendar Events

> Use event_styles rules to apply colors, icons, opacity, and hide overrides to Home Assistant calendar events matched by title, calendar, location, or date.

The `event_styles` configuration lets you define a list of rules that change how individual events look on your calendar. Each rule specifies which events to target through a `match` object and how to style them through a `style` object. When multiple rules match the same event, conflicts are resolved per style property: the matching rule with the highest `priority` for that property wins. This makes it easy to build layered styling — for example, dimming all past events while still highlighting specific recurring ones at a higher priority.

## Rule Structure

Each entry in `event_styles` is a rule with the following top-level keys:

* **`match`** — describes which events the rule applies to. `when` is accepted as an alias.
* **`style`** — describes how matching events should look
* **`priority`** — optional integer (default `0`) that controls which rule wins when multiple rules set the same style property
* **`id`** — optional string identifier. Auto-generated (`event-style-1`, `event-style-2`, …) if omitted.

<Tip>
  `event_styles`, `day_styles`, and `day_badges` all share the same advanced match schema. Anything you learn here applies to the other two rule types.
</Tip>

<Tip>
  For one-off, per-device recoloring — for example, giving a single event a distinctive color on the family dashboard without changing the calendar — use the [Custom Color](/configuration/event-management#custom-event-colors) action in the event detail modal instead of `event_styles`. Modal overrides win over the `color` / `background_color` set here, but do not affect other style properties.
</Tip>

## Advanced match schema

The `match` object supports two scopes and the standard logical operators:

* **`match.event`** — event-scoped conditions (title, calendar, all\_day, etc.). For `event_styles`, fields written at the top level of `match` are implicitly treated as event conditions, so `match: { title: 'standup' }` and `match: { event: { title: 'standup' } }` are equivalent.
* **`match.day`** — day-scoped conditions (`today`, `weekend`, `has_event`, …). See [Day match fields](/advanced/day-styles#day-match-fields) for the full list. Useful when you want a rule to fire only on certain dates, e.g. weekdays.
* **`match.any` / `match.all` / `match.and` / `match.not`** — combine nested match blocks with OR / AND / NOT logic.

### Example: match a calendar only on weekdays

```yaml theme={null}
event_styles:
  - match:
      event:
        calendar: calendar.work
      day:
        weekday: true
    style:
      color: '#1565C0'
      font_color: '#ffffff'
```

## Event match fields

Use one or more of the following fields inside `match` (or `match.event`) to filter by event properties. By default, an event must satisfy **all** specified fields to be considered a match. For OR / NOT logic, use the [logical operators](#logical-operators) below.

<ParamField path="match.calendar" type="string | object">
  A calendar entity ID or substring to match against an event's calendar identifiers. Plain strings use case-insensitive substring matching. Use an `exact` matcher object when an exact value is required. Aliases: `calendar_entity`, `entity_id`, `entity`.
</ParamField>

<ParamField path="match.title" type="string | object">
  A substring to look for in the event title. The match is case-insensitive. You can also pass a regex pattern wrapped in forward slashes, e.g. `/standup/i`. Alias: `title_contains: foo` is equivalent to `title: 'contains:foo'`.
</ParamField>

<ParamField path="match.summary" type="string | object">
  Alias for `match.title`. Both names map to the event summary field. Use whichever feels more natural. Alias: `summary_contains`.
</ParamField>

<ParamField path="match.description" type="string | object">
  A substring to look for in the event description field. Alias: `description_contains`.
</ParamField>

<ParamField path="match.location" type="string | object">
  A substring to look for in the event location field. Alias: `location_contains`.
</ParamField>

<ParamField path="match.all_day" type="boolean">
  When `true`, only matches all-day events. When `false`, only matches timed events. Alias: `all_day_event`.
</ParamField>

<ParamField path="match.past" type="boolean">
  When `true`, only matches events whose end time is in the past. When `false`, only matches events that are not yet past.
</ParamField>

## Text matching

Plain strings for `title`, `summary`, `description`, `location`, and `calendar` use case-insensitive substring matching by default. Use this simple form for most rules:

```yaml theme={null}
match:
  title: "Dentist"
```

For explicit matching, these fields also accept an object with one of the following operators:

* `title: { exact: "Dentist" }` matches the complete value.
* `title: { contains: "Dentist" }` uses substring matching.
* `title: { substring: "Dentist" }` is equivalent to `contains`.
* `title: { regex: "^Dentist appointment$" }` uses a regular expression.

Each text operator accepts a **single string**, not a YAML array. For example, this is invalid:

```yaml theme={null}
title:
  contains: ["Dentist"] # Invalid
```

To match multiple possible values, put separate conditions in `match.any`:

```yaml theme={null}
match:
  any:
    - title: "Dentist"
    - title: "Annual Leave"
```

Arrays belong to logical operators such as `any` and `all`, not text operators such as `contains`. Event conditions nested in `day_styles` or `day_badges` use the same text matching rules, but follow each rule type's scoping syntax.

## Logical Operators

For compound rules, `match` supports four logical operator keys. `any`, `all`, `and`, and `not` each accept either a single sub-condition object or an array of sub-condition objects. Arrays are typically used when combining multiple conditions. Sub-conditions use the same match-field syntax as a top-level `match` block, including nested operators.

<ParamField path="match.any" type="object | array">
  OR logic. The rule matches when **at least one** of the listed sub-conditions matches.
</ParamField>

<ParamField path="match.all" type="object | array">
  AND logic. The rule matches when **all** listed sub-conditions match. Same as combining fields at the top level, but useful when nesting inside `any` or `not`.
</ParamField>

<ParamField path="match.and" type="object | array">
  Alias for `match.all`.
</ParamField>

<ParamField path="match.not" type="object | array">
  NOT logic. The rule matches when the sub-condition does not match. When given an array, the rule matches only when none of the listed sub-conditions match.
</ParamField>

### Example: events on the work OR personal calendar

```yaml theme={null}
event_styles:
  - match:
      any:
        - calendar: calendar.work
        - calendar: calendar.personal
    style:
      opacity: 0.6
```

### Example: all-day events that are NOT in the past

```yaml theme={null}
event_styles:
  - match:
      all_day: true
      not:
        past: true
    style:
      color: '#1565C0'
      font_color: '#ffffff'
```

## Style Fields

The `style` object accepts the following properties to control how matched events are rendered.

<ParamField path="style.color" type="string">
  Alias for `style.background_color`. Hex color string (e.g. `'#1565C0'`) applied to the event's background or bar color.
</ParamField>

<ParamField path="style.background_color" type="string">
  Hex color string applied to the event's background or bar color. Equivalent to `style.color`.
</ParamField>

<ParamField path="style.font_color" type="string">
  Hex color string applied to the event's text. Use this to ensure readable contrast when you change the background color.
</ParamField>

<ParamField path="style.display_title" type="string">
  Replaces the event title shown in the card with a nonempty fixed string. This changes only the card display; matching, event details, editing, and the source calendar event continue to use the original title.
</ParamField>

```yaml theme={null}
event_styles:
  - match:
      calendar: calendar.family
      title:
        exact: "My Long Title Event"
    style:
      display_title: "My Event"
```

A plain `match.title` string uses case-insensitive substring matching against the original event title. Use `title: { exact: "…" }`, as shown above, when the alias should apply only to the complete original title.

<ParamField path="style.opacity" type="number">
  A number between `0` and `1` that controls the event's transparency. Use `0.4` to visually mute events without hiding them entirely.
</ParamField>

<ParamField path="style.filter" type="string">
  A CSS filter string applied to the event element. For example, `grayscale(100%)` removes all color from matching events.
</ParamField>

<ParamField path="style.icon" type="string">
  An MDI icon name (e.g. `mdi:repeat`) to attach to matching events. Combine with `icon_position` to control placement.
</ParamField>

<ParamField path="style.icon_position" default="before_title" type="string">
  Controls where the icon is rendered. Use `before_title` to place it inline before the event title, or `corner` to display it as a small overlay in the corner of the event chip.
</ParamField>

<ParamField path="style.icon_color" type="string">
  Hex color string applied to the matched style icon. Defaults to the event's text color.
</ParamField>

<ParamField path="style.icon_size" type="string | number">
  Overrides the icon size. Accepts a number (interpreted as pixels) or any CSS length string such as `'14px'` or `'1.1em'`.
</ParamField>

<ParamField path="style.hide" type="boolean">
  When `true`, matching events are completely removed from the calendar view. Hidden events are not counted toward day event totals.
</ParamField>

<ParamField path="style.hide_time" type="boolean">
  When `true`, suppresses the time label on matching events even if times would otherwise be shown.
</ParamField>

<ParamField path="style.show_time" type="boolean">
  When `true`, forces the time label to render on matching events even if it would otherwise be hidden (for example, by `hide_times_for_calendars`).
</ParamField>

<ParamField path="style.hide_event_calendar_bubble" type="boolean">
  When `true`, hides the small calendar-color dot on matching events. Useful when you've added a custom `icon` and don't want the default indicator competing with it.
</ParamField>

<ParamField path="style.show_event_location" type="boolean">
  Per-rule override of the global `show_event_location` setting. Set to `true` to force locations on for matching events, or `false` to hide them on matching events only.
</ParamField>

<ParamField path="style.use_short_location" type="boolean">
  Per-rule override of the global `use_short_location` setting.
</ParamField>

<ParamField path="style.event_font_size" type="string | number">
  Per-rule override of the event title font size. Accepts a number (pixels) or CSS length string.
</ParamField>

<ParamField path="style.event_time_font_size" type="string | number">
  Per-rule override of the event time font size. Accepts a number (pixels) or CSS length string.
</ParamField>

<ParamField path="style.event_location_font_size" type="string | number">
  Per-rule override of the event location font size. Accepts a number (pixels) or CSS length string.
</ParamField>

<ParamField path="style.event_title_prefix" type="string">
  Per-rule override of the global `event_title_prefix` mode. Accepted values: `none`, `badge_icon`, `friendly_name`.
</ParamField>

## Priority

<ParamField path="priority" default="0" type="integer">
  When two or more rules match the same event, conflicts are resolved **per style property**. For each property, the rule with the highest `priority` wins. If priorities are equal, the rule defined earlier in the list wins. Properties that aren't set by the winning rule fall through to the next matching rule, so styles from different rules can compose on the same event.
</ParamField>

<Tip>
  Use `priority` to layer general rules with specific overrides. For example, set a low-priority rule that dims all past events, then add a high-priority rule that keeps a specific calendar's events fully visible regardless.
</Tip>

## Examples

### Color all events from a work calendar

This rule applies a deep blue background and white text to every event from `calendar.work`.

```yaml theme={null}
event_styles:
  - match:
      calendar: calendar.work
    style:
      color: '#1565C0'
      font_color: '#ffffff'
```

### Hide events titled "Free"

This rule completely removes any event whose title contains the word "Free" from the calendar view.

```yaml theme={null}
event_styles:
  - match:
      title: 'Free'
    style:
      hide: true
```

### Add a corner icon to a specific calendar's events

This rule stamps a briefcase icon in the corner of every event from `calendar.work`. A `priority` of `5` ensures it takes precedence over lower-priority color rules.

```yaml theme={null}
event_styles:
  - match:
      calendar: calendar.work
    style:
      icon: mdi:briefcase
      icon_position: corner
    priority: 5
```

### Mute all-day events with opacity

This rule reduces the opacity of all-day events to `0.4`, visually de-emphasizing them without hiding them.

```yaml theme={null}
event_styles:
  - match:
      all_day: true
    style:
      opacity: 0.4
    priority: 1
```

### Dim past events

This rule applies a grayscale filter and reduced opacity to any event that has already passed, giving the calendar a clear visual split between past and upcoming.

```yaml theme={null}
event_styles:
  - match:
      past: true
    style:
      filter: 'grayscale(100%)'
      opacity: 0.5
    priority: 1
```

### Combine multiple match conditions

You can narrow a rule by specifying more than one match field at the same time. This rule applies a grayscale filter only to past all-day events from a specific calendar.

```yaml theme={null}
event_styles:
  - match:
      calendar: calendar.holidays
      all_day: true
      past: true
    style:
      filter: 'grayscale(100%)'
      opacity: 0.5
    priority: 2
```

<Note>
  All style values are sanitized before they are applied to the DOM. Attempting to inject HTML or JavaScript through a `color`, `filter`, or other style field will be stripped out automatically.
</Note>
