<bmx-recurrence-editor>
The "repeat" part of a meeting, a report schedule, a maintenance window or a recurring invoice: how often, which days, from when, until when - shown as the handful of choices calendar programs use, and written as the iCalendar rule (RFC 5545) every calendar and scheduling library reads, or as a cron expression for a job runner.
25 properties · 1 events · 4 methods · 9 parts
Example
Show markup
<div class="row" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); gap: 24px; align-items: start">
<div style="display: grid; gap: 12px">
<bmx-recurrence-editor id="ex-re-meeting" label="Team review repeats" name="repeat" value="FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,TH" start="2026-11-03T09:30" time-zone="Europe/London" preview="4" show-rule description="Skip a date from the list to leave it out of the series."></bmx-recurrence-editor>
<pre class="note" id="ex-re-out" role="status" style="margin: 0; white-space: pre-wrap; font-size: 12px"></pre>
</div>
<bmx-recurrence-editor id="ex-re-job" label="Run the nightly export" value-format="cron" cron-dialect="quartz" value="0 30 2 ? * 2-6 *" time-zone="UTC" preview="3" show-rule description="Quartz cron, for a job scheduler."></bmx-recurrence-editor>
</div>
<script type="module">
await customElements.whenDefined('bmx-recurrence-editor');
const meeting = document.getElementById('ex-re-meeting');
const out = document.getElementById('ex-re-out');
const show = async () => (out.textContent = await meeting.toICalendar());
meeting.addEventListener('bmxChange', show);
show();
</script>
<bmx-recurrence-editor label="Repeats" name="repeat"
value="FREQ=WEEKLY;BYDAY=MO,WE,FR" start="2026-10-12T09:00"
time-zone="Europe/London"></bmx-recurrence-editor>
<bmx-recurrence-editor label="Run the export" value-format="cron"
value="30 6 * * 1-5"></bmx-recurrence-editor>
The choices: daily (every n days or every weekday), weekly (every n weeks on
the days ticked), monthly and yearly (on a date, or on "the second Tuesday",
"the last weekday", "the first weekend day"), and an end (never, after n
times, or on a date). A summary in words follows every change, and the next
occurrences are listed in the series' own time zone - at the same wall-clock
time either side of a change of clocks - with a Skip button on each, which
adds the date to exceptions (EXDATE). A rule the choices cannot show is
kept exactly as written and can be edited as text.
With value-format="cron", the value is a cron expression (Unix, or Quartz
with cron-dialect="quartz", which adds the last and nth day of a month);
choices cron cannot express are flagged rather than silently changed.
Nothing is stored or sent: the value goes to the form under name and out
in bmxChange with the cron form, the summary and ready-made iCalendar
lines.
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
allowSkip |
allow-skip |
boolean |
true |
Let the reader skip occurrences from the list. |
cronDialect |
cron-dialect |
BmxCronDialect |
'unix' |
The cron dialect written and read: Unix (five fields) or Quartz (seven, with L, # and W). |
describe |
property only | BmxRecurrenceDescribe |
— | Replaces the summary in words. |
description |
description |
string |
— | Help text below the control. |
disabled |
disabled |
boolean |
false |
Disable the control. |
errorText |
error-text |
string |
— | An error supplied by the page. |
exceptions |
exceptions |
string[] | string |
[] |
Dates skipped (EXDATE), YYYY-MM-DD, as an array, JSON or a comma list. Two-way. |
formValue |
form-value |
'value' | 'icalendar' |
'value' |
What the form receives under name: the value, or the whole series as iCalendar lines. |
frequencies |
frequencies |
BmxRecurrenceRepeat[] | string |
— | The choices offered for Repeat, as an array, JSON or a comma list of none, daily, weekly, monthly, yearly. |
hideLabel |
hide-label |
boolean |
false |
Hide the label visually while keeping it as the accessible name. |
label |
label |
string |
— | The field's label: names the whole control. |
locale |
locale |
string |
— | The language for day and month names and dates. Default: the page's. |
name |
name |
string |
— | The field's name in a form. |
preview |
preview |
number |
5 |
How many next occurrences to list; 0 hides the list. |
readonly |
readonly |
boolean |
false |
Show the rule without letting it change. |
required |
required |
boolean |
false |
It must repeat: "does not repeat" is not a valid answer. |
showEnd |
show-end |
boolean |
true |
Show the end choices. |
showRule |
show-rule |
boolean |
false |
Show the iCalendar rule and cron text, with copying and editing as text. |
showStart |
show-start |
boolean |
true |
Show the start date and time. |
start |
start |
string |
— | The first occurrence, as wall-clock time in time-zone: 2026-10-12T09:00, or a date alone (09:00). Default: today at 09:00. Two-way. |
strings |
strings |
Partial<BmxRecurrenceEditorStrings> | string |
— | Words to show instead of the English ones, as an object or JSON. |
timeZone |
time-zone |
string |
— | The series' IANA time zone, such as Europe/London. Default: the reader's own. |
value |
value |
string |
'' |
The rule: iCalendar text such as FREQ=WEEKLY;BYDAY=MO (with or without RRULE:), or a cron expression when value-format="cron". '' does not repeat. Two-way. |
valueFormat |
value-format |
'rrule' | 'cron' |
'rrule' |
What value holds: an iCalendar rule, or a cron expression. |
weekStart |
week-start |
number |
— | The first day of the week, 0 for Sunday. Default: the locale's. |
Events
| Event | Detail | Description |
|---|---|---|
bmxChange |
BmxRecurrenceDetail |
Fired after the reader changes the rule, the start or the skipped dates. |
Methods
| Method | Signature | Description |
|---|---|---|
getOccurrences |
getOccurrences(count?: number, from?: string | number) => Promise<BmxRecurrenceOccurrenceDetail[]> |
The next occurrences from from (an ISO instant or milliseconds; default now), skipped ones included and marked. |
getRule |
getRule() => Promise<BmxRecurrenceDetail> |
The rule in every form: value, iCalendar rule, cron, words, start, zone, skipped dates and iCalendar lines. |
setFocus |
setFocus() => Promise<void> |
Moves focus to the Repeat choice. |
toICalendar |
toICalendar() => Promise<string> |
DTSTART, RRULE and EXDATE lines, joined with CRLF, for an iCalendar VEVENT. |
Slots
| Slot | Description |
|---|---|
description |
Rich help text, in place of the description property. |
label |
Rich label content, in place of the label property. |
CSS shadow parts
| Part | Description |
|---|---|
day |
A day-of-the-week button; also day-pressed. |
description |
The help text under the field. |
label |
The label element. |
occurrence |
One of them; also occurrence-skipped. |
output |
The rule and cron text. |
panel |
The box holding the choices. |
preview |
The list of next occurrences. |
row |
One row of choices. |
summary |
The rule in words. |
CSS custom properties
| Property | Description |
|---|---|
--bmx-recurrence-editor-background |
The panel's background. |
--bmx-recurrence-editor-day-size |
Size of a day-of-the-week button. |
--bmx-recurrence-editor-label-font-size |
The label's font size. |
--bmx-recurrence-editor-label-width |
Width of the row labels (Repeat, Starts, Ends). |
--bmx-recurrence-editor-radius |
Corner radius of the panel. |
--bmx-recurrence-editor-support-font-size |
Font size of the description and error message. |