# Schedule field

A job’s schedule set as one sentence, in place of a raw cron text input or five selects. A segmented control picks the frequency (hour, day, week or month); weekday keys, a time field, a minute past the hour or a day of the month finish it, and the sentence reads it back as words: “Every weekday at 09:00”, “Every Monday and Thursday at 18:30”. Under it an LCD strip prints the next three run times in the zone the job runs in, counted across clock changes, and they move as you change anything. A small mono line shows the cron and can be typed: a valid line moves the controls, a line the sentence cannot say reads “Custom schedule” and hides the days and the time, a wrong one puts an error on the whole well and leaves the last good line in the form. It posts the cron (5 fields) under its name. Times are wall-clock times in the zone printed on the strip: a time the clock skips (03:30 on the spring-forward night) runs when the clock jumps, a time it repeats runs once, and a month without the chosen day of the month is skipped.

Kit part · With the Kit · https://tactileui.dev/parts/schedule-field

> The code and styling for this part come with the Tactile UI Kit, which the Pass and the Founder Pass include. Sign in if you have it. Sign in: https://tactileui.dev/auth/sign-in The price: https://tactileui.dev/pricing

## Anatomy

It is made of the kit’s own parts, used as shipped: the segmented control for the frequency, toggle keys for the days and the presets, the time field for the time, the field’s well and its red error pattern, and the LCD for the runs. The script is the sentence in between: a cron parser (numbers, lists, ranges, steps), the two-way map between the controls and a cron line (null for a line the controls cannot say), and the run counter. The counter walks the days from today in the wall clock of the zone, read with Intl.DateTimeFormat (no library); on a day with no clock change one offset serves the whole day, and on a day with one every time is checked against the zone, so a skipped time runs when the clock jumps and a repeated time runs once. The field is form-associated: the value in a FormData is the last good cron line.

## Variants

- Every weekday · week
- Two days · week
- Every hour · hour
- Every day · day
- Every month · month
- Last days of the month · months without it are skipped
- A line the sentence cannot say · Custom schedule
- Another zone
- Disabled · disabled

## States

- Default
- Custom schedule

## Props and options

| Name | Kind | Description |
| - | - | - |
| value | attribute, property | The cron line (minute, hour, day of month, month, day of week). It is the default a reset goes back to. As a property it is always the last good line. |
| timezone | attribute | The zone the times are in, printed once on the strip. An unknown zone falls back to the browser’s. |
| now | attribute | Where the next runs are counted from; for demos and tests. |
| schedule · nextRuns(count) | properties | The controls’ reading of the line (null for a custom one) and the next run times as Dates. |
| input · change | events | input as the line changes, change when it is committed (a control changed, or the cron line left or Enter pressed). The inner controls’ own events stop at the field. |
| parseCron(cron) | function | Numbers, *, lists, ranges, steps, month and day names, 7 for Sunday. |
| scheduleToCron(s) · cronToSchedule(cron) | functions | The controls to a cron line, or null when they do not make one; a cron line to the controls, or null (custom) when the sentence cannot say it. |
| scheduleSentence(s) | function | The words: “Every weekday at 09:00”, “Every hour at :15”, “Every month on the 1st at 06:00”; “Custom schedule” for null. |
| nextRuns(cron, from, count, timeZone) | function | The next run times as Dates, in the wall clock of the zone: a skipped time runs when the clock jumps, a repeated one runs once, a month without the day is skipped. |

## Usage notes

Press Week, then the Mon and Thu keys: the sentence and the strip follow. Week opens with Monday to Friday down. Type 0 9 * * to the cron line and leave it: the well turns red and the form keeps the last good line. Press Month and set the day to 31: months without a 31st are skipped in the strip.

## Accessibility

- Keyboard: Tab goes through the frequency (the arrow keys choose within it), the weekday keys, the time, the cron line; Space or Enter presses a key; Enter in the cron line commits it and does not send the form while it is wrong. Every control is the kit’s own, with its own keys and focus ring.
- The whole field is a group named by its label. The weekday keys are named by the full day (“Monday”) and carry aria-pressed; the frequency is a radio group.
- A polite status line reads the sentence and the first next run after a change: “Every weekday at 09:00. The LCD strip is a list of the next runs, each read in words.
- It shows once the cron line is left or Enter is pressed, and clears as soon as the line reads.

## Related parts

- [Time field](https://tactileui.dev/parts/time-field): A time of day in the field’s well: hours, minutes and, on a 12 hour clock, AM or PM, each a segment you can type into or step with the arrow keys. A key at the right opens a plain list of times, every few minutes between the earliest and the latest you allow, with the current one in the middle. It posts “HH:MM” on the 24 hour clock whichever clock it shows, says what is wrong in words (empty, half typed, too early, too late, off the step), and works in a native form, with a label, help text, an error, a disabled state and a reset.
- [Segmented control](https://tactileui.dev/parts/segmented): A row of keys in a tray with one pressed down: pick a view, a range or a mode and it applies at once. It is the kit’s selector without the lamps, with sizes, a full-width row and icon segments.
- [Toggle key](https://tactileui.dev/parts/toggle-key): One key that latches below the plate and stays there. It is the kit’s own key with one state to keep, down or up, so it is the way to say mute, pin, bold or armed without the weight of a switch. A lamp in the cap may light while it is down.
