# Availability Viewer

The Availability Viewer Element is an interactive week-based display of availability. It converts an [availability query](/developers/api/scheduling/availability/index.md) into a grid of days with free/busy times displayed. If the requested available periods span more than one week, the user can browse those weeks with the provided navigation buttons. Users can pre-select an available slot for any available block of time, and then confirm that slot with a button-click. When a user confirms a slot, the element passes that slot's details into a callback function (provided when the element is initialized).

### Demo
*(Interactive UI element — see the HTML version for the live demo)*

### Example initialization
```html
<div id="cronofy-availability-viewer"></div>
<script src="https://elements.cronofy.com/js/CronofyElements.v1.67.6.js"></script>
<script>
    CronofyElements.AvailabilityViewer({
        element_token: "{ELEMENT_TOKEN}",
        target_id: "cronofy-availability-viewer",
        availability_query: {
            participants: [
                {
                    required: "all",
                    members: [
                        { sub: "acc_5ba21743f408617d1269ea1e" },
                        { sub: "acc_64b17d868090ea21640c914c" }
                    ]
                }
            ],
            required_duration: { minutes: 60 },
            query_periods: [
                { start: "2026-04-21T09:00:00Z", end: "2026-04-21T17:00:00Z" },
                { start: "2026-04-22T09:00:00Z", end: "2026-04-22T17:00:00Z" },
                { start: "2026-04-23T09:00:00Z", end: "2026-04-23T17:00:00Z" },
                { start: "2026-04-24T09:00:00Z", end: "2026-04-24T17:00:00Z" }
            ],
        },
        config: {
            start_time: "09:00",
            end_time: "15:30",
            interval: 15
        },
        styles: {
            prefix: "custom-name"
        },
        callback: notification => console.log("callback", notification),
    });
</script>
```

### Element permissions
`availability` is required when generating the [Element Token](/developers/ui-elements/authentication/index.md).

### Element options
##### `element_token` *(required)*

The [Element Token](/developers/ui-elements/authentication/index.md) the
Availability Viewer will use to communicate with Cronofy.

*Not required if the Element is activated in demo mode.*

##### `target_id` *(required)*

The ID of the DOM node the Element will be loaded in to.

##### `callback` *(required)*

The function to be called when an action has occurred within the Element. Receives an object in the format:

```json
{
    "notification": {
        "type": "notification_type"
    }
}
```

The object will always include a `notification` object with a `type` attribute to allow you to determine how to handle it. Your application should ignore notifications it does not understand as new ones may be added in future.

###### slot_selected
Sent by the Element when in the `confirm` mode after the user has confirmed
their selection, and straight away when the slot is selected in `no_confirm`
mode.

```js
{
    "notification": {
        "type": "slot_selected"
        "slot": {
            "start": "2026-04-21T09:00:00Z",
            "end": "2026-04-21T11:00:00Z",
            "participants": [
                { "sub": "acc_5ba21743f408617d1269ea1e" },
                { "sub": "acc_64b17d868090ea21640c914c" }
            ]
        }
    }
}
```

###### slot_added
Sent by the Element when in the `multi_select` mode after the user has added a
slot to their selection.

```js
{
    "notification": {
        "type": "slot_added"
        "slot": {
            "start": "2026-04-21T09:00:00Z",
            "end": "2026-04-21T11:00:00Z",
            "participants": [
                { "sub": "acc_5ba21743f408617d1269ea1e" },
                { "sub": "acc_64b17d868090ea21640c914c" }
            ]
        }
    },
    "slots": [
        {
            "start": "2026-04-21T09:00:00Z",
            "end": "2026-04-21T11:00:00Z",
            "participants": [
                { "sub": "acc_5ba21743f408617d1269ea1e" },
                { "sub": "acc_64b17d868090ea21640c914c" }
            ]
        }
    ]
}
```

`slots` includes all selected slots, including the one that was selected to
generate the notification.

###### slot_removed
Sent by the Element when in the `multi_select` mode after the user has removed a
slot from their selection.

```js
{
    "notification": {
        "type": "slot_removed"
        "slot": {
            "start": "2026-04-21T09:00:00Z",
            "end": "2026-04-21T11:00:00Z",
            "participants": [
                { "sub": "acc_5ba21743f408617d1269ea1e" },
                { "sub": "acc_64b17d868090ea21640c914c" }
            ]
        }
    },
    "slots": []
}
```

`slots` includes all selected slots and so will not include the one that was
removed to generate the notification.

###### no_slots_found
Sent by the Element when the provided `availability_query` has returned no available slots.

```js
{
    "notification": {
        "type": "no_slots_found",
        "query": {
          "available_periods": AVAILABLE_PERIODS,
          "participants": PARICIPANTS,
          "required_duration": {"minutes": 60},
          "response_format": "overlapping_slots",
          "start_interval": {"minutes": 15}
    }
}
```

> **INFO:** **Note:** while the Slot Picker `no_slots_found` notification contains only a `type` field, the Availability Viewer version also includes a `query`. This is because the Availability Viewer crops the provided `availability_query` to fit within the bounds of the visible slots grid.

###### no_visible_slots
Sent by the Element when the provided `availability_query` has returned no available slots for the period currently displayed on the Element's grid. This is distinct from the `no_slots_found` notification because it will only be fired if there are no available periods visible, but at least one available slot within the provided query as a whole (i.e. the availability is found on a week not currently shown, but accessible via the Element's internal navigation).

```js
{
    "notification": {
        "type": "no_visible_slots",
    }
}
```

###### visible_slots
Sent by the Element when the provided `availability_query` has returned some available slots for the period currently displayed on the Element's grid. This can be used to clear any warnings or state prompted by the `no_visible_slots` notification.

```js
{
    "notification": {
        "type": "visible_slots",
    }
}
```

###### query_periods_edited
Sent by the Element when in `free_select` mode whenever a slot is toggled between "available" and "unavailable". Returns an array of all the currently selected available slots combined into `query_periods` compatible with a valid Cronofy [Availability request](/developers/api/scheduling/availability/index.md).

```js
{
    "notification": {
        "type": "query_periods_edited",
        "query_periods": [
            // The selected query_periods
            { "start": "2020-07-18T09:00:00Z", "end": "2020-07-18T13:30:00Z" },
            { "start": "2020-07-19T09:00:00Z", "end": "2020-07-19T13:30:00Z" },
            { "start": "2020-07-20T09:00:00Z", "end": "2020-07-20T13:30:00Z" },
            { "start": "2020-07-21T09:00:00Z", "end": "2020-07-21T13:30:00Z" }
        ]
    }
}
```

###### displayed_dates_changed
Sent by the Element when a user changes the range of dates they are viewing. Returns the first and last days being shown as well as information regarding the pagination state.
This can be especially useful when combined with [navigations](/developers/ui-elements/availability-viewer/index.md).

```js
{
    "notification": {
        "type": "displayed_dates_changed",
        "firstDay": "2021-09-13",
        "lastDay": "2021-09-20",
        "hasNext": true,
        "hasPrev": false,
    }
}
```

##### `availability_query` *(required)*

Object that matches a valid Cronofy [Availability request](/developers/api/scheduling/availability/index.md).

> **INFO:** The Availability Viewer only ever queries for availability for the currently-displayed week. This means that the normal [35-day maximum for `query_periods`](/developers/api/scheduling/availability/index.md) does not apply. As a result, `query_periods` for the Availability Viewer can span many months, up to the limit of [201 days in the future](/developers/api/scheduling/availability/index.md).

##### `config` *(optional)*

Use this object to add further limits to the availability display:

##### `config.start_time` *(optional)*

Hide any available slots before this time. Defaults to `&quot;09:00&quot;`.

Must be an increment of 15 minutes (for example, `&quot;HH:00&quot;`, `&quot;HH:15&quot;`, `&quot;HH:30&quot;`, and `&quot;HH:45&quot;`). Any other times will be rounded down to the nearest multiple of 15 minutes.

##### `config.end_time` *(optional)*

Hide any available slots after this time. Defaults to `&quot;17:00&quot;`.

Must be an increment of 15 minutes (for example, `&quot;HH:00&quot;`, `&quot;HH:15&quot;`, `&quot;HH:30&quot;`, and `&quot;HH:45&quot;`). Any other times will be rounded up to the nearest multiple of 15 minutes.

##### `config.interval` *(optional)*

When selecting a slot, the available options are staggered by this amount. Defaults to `15`. Currently supported values are `15`, `30`, and `60`. Any other numbers will be rounded to the nearest multiple of 15, and any values over 60 will be rounded down to 60.

> **INFO:** To ensure optimal tessellation of the grid, if the provided `config.interval` is greater than the difference between the `config.start_time` and the top of an hour, then the interval will be adjusted to intersect the hour. For example, if the interval is `60` but the start time is `&quot;08:30&quot;`, then an interval of `30` will be used. If the provided interval is `60` but the start_time is `&quot;08:45&quot;`, then an interval of `15` will be used. This ensures that the Availability Viewer's grid matches the [API's `start_interval` rules](/developers/api/scheduling/availability/index.md).

##### `config.mode` *(optional)*

The Availability Viewer element has several "modes" it can operate in:

- `confirm` (default)

- `no_confirm`

- `multi_select`

- `free_select`

When in `confirm` mode, clicking a slot once marks it as selected. Clicking a selected slot confirms the selection and fires the provided callback with a single slot object.

When in `no_confirm` mode, the "confirmation" step is skipped. Clicking any slot will fire the callback.

When in `multi_select` mode, you can select as many slots as you like. Every time a slot is clicked, the callback is fired with an object in the following format:

```js
{
    "notification": {
        "type": "slot_removed",
        "slot": {
            // The details of the clicked slot.
        }
    }
    "slots": [
        // An array of all currently selected slots.
    ]
}
```

In this scenario, `notification.type` is either `slot_added` or `slot_removed` depending on whether the most recently clicked slot has been selected or deselected.

When in `free_select` mode, the Availability Viewer becomes a `query_period` generator.

- The week grid switches to show the next 7 days of availability, starting on the current day, and will allow access to all weeks covering the next 35 days using the week navigation buttons. This is in line with the [maximum length of an availability query within the API](/developers/api/scheduling/availability/index.md).

- Rather than displaying which periods you are available for, when in `free_select` mode the Availability Viewer will display any upcoming events in your calendar as "booked", and then allows to toggle any slot between "available" and "unavailable". Whenever the selected availability is changed, the [`query_periods_edited` notification](#query-periods-edited) will be fired:

```js
{
    "notification": {
        "type": "query_periods_edited",
        "query_periods": [
            // The selected query_periods
            { "start": "2020-07-18T09:00:00Z", "end": "2020-07-18T13:30:00Z" },
            { "start": "2020-07-19T09:00:00Z", "end": "2020-07-19T13:30:00Z" },
            { "start": "2020-07-20T09:00:00Z", "end": "2020-07-20T13:30:00Z" },
            { "start": "2020-07-21T09:00:00Z", "end": "2020-07-21T13:30:00Z" }
        ]
    }
}
```

If no slots are selected, the `query_periods_edited` notification will be called with `notification.query_periods` set to an empty array.

> **INFO:** When the time-expansion arrows are used to contract the size of the visible grid, any `free_select` selection that falls outside of the visible area will be removed from the `query_periods` included in the selection notification.

##### `config.max_selection_count` *(optional)*

When `config.mode` is set to `multi_select`, it is possible to limit the amount of slots that can be selected at any one time. If `config.mode` is set to anything other than `multi_select`, this parameter will be ignored. Accepts an `Integer` or `false`. `false` explicitly applies no limit, and is the default value.

##### `config.bounds_control` *(optional)*

If the `config.bounds_control` option is set as `true`, users can dynamically change the start and end times of the Availability Viewer element. This is handled by a start/end time modal activated by clicking a cog icon that appears above the times label column. The default value is `false`.

##### `config.allow_expansion` *(optional)*

This option shows the time-expansion arrows in all modes. The time-expansion arrows allow the visible grid of slots to be expanded to midnight (both to the start and the end of the day). These arrows are always visible when `mode.free_select` is active, but this option can be used to expose the same time-expansion functionality in other modes.

##### `config.slot_selection` *(optional)*

Controls the slot-selection behavior. Takes a string with two possible values: `available` or `unrestricted`. The default of "available" means only *available* slots can be selected. Setting this option to "unrestricted" will allow any slot (available and unavailable) to be selected.

In both instances, the `config.mode` will still be honored. So if the mode is `no_confirm`, the notification callback will be fired every time a slot is clicked, but if the mode is `confirm` (the default) then the notification will only be fired when a slot is confirmed (the second click after it has been selected).

When this parameter is set to `unrestricted`, a boolean "available" attribute is added to the slot objects that are returned by the notification (`notification.slot.available`). This reflects the availability of the slot (`true` for available, `false` for unavailable).

Note, when the Availability Viewer is loaded in "unrestricted" mode, the "hover-slot" indicator will display the full duration (e.g. 60mins, if a duration of `60` has been set) when hovering unavailable slots, and the tooltip will switch from displaying "unavailable" to showing the start/end times for the slot (matching the behavior currently shown for available slots). There will be a corresponding `--unavailable` modifier added to the `hover-slot` class.

##### `config.logs` *(optional)*

Set the level of logging you want to appear in the console:

- `info`: show verbose logging (recommended for development use only).

- `warn`: (default) only log errors and warnings.

- `error`: only log errors.

- `none`: suppress all console output from the Element.

##### `config.week_start_day` *(optional)*

The day of the week that the view will start on. For example, setting `config.week_start_day: &quot;tuesday&quot;` will display the UI Element's week-grid as `Tue | Wed | Thu | Fri | Sat | Sun | Mon`

Defaults to `sunday`.

Valid options are:

- `sunday`

- `monday`

- `tuesday`

- `wednesday`

- `thursday`

- `friday`

- `saturday`

Please be aware that it is not possible to hide certain days from being shown in the Availability Viewer UI element.

##### `data_center` *(optional)*

Designates the Cronofy data center the Element will communicate with.

Default value is `us`.

##### `locale` *(optional)*

The Availability Viewer supports localization (e.g. `locale: &quot;fr&quot;` to load in French). Defaults to browser language setting.

Supported locales (languages) for the UI Elements are:

- `ar` Arabic

- `cs` Czech

- `cy` Welsh

- `de` German

- `en` US English (default)

- `es` Spanish

- `fr` French

- `fr-CA` Canadian French

- `he` Hebrew

- `it` Italian

- `ja` Japanese

- `nl` Dutch

- `pl` Polish

- `pt-BR` Brazilian Portuguese

- `ru` Russian

- `sv` Swedish

- `tr` Turkish

- `zh-CN` Simplified Chinese

##### `translations` *(optional)*

To override either a locale or a particular string, pass in a translations object here. The Availability Viewer uses the `avialability_viewer` translation "context".

[Read more about customizing translations](/developers/ui-elements/customization/index.md)

##### `demo` *(optional)*

Boolean to activate demo-mode. Defaults to `false`. If `demo` is set to `true` the element will return mock data (and not make any API calls).

##### `styles` *(optional)*

An object that controls the pre-packaged element styles.

##### `styles.prefix` *(optional)*

Customizable elements are given a prefixed class name using this value. For example, if the `prefix` was set as "Foo", the class name on a slot element would be `Foo__slot`. Defaults to the name of the element (e.g. `&quot;AvailabilityViewer&quot;`).

##### `styles.colors` *(optional)*

Use these options to set the colors for various parts of the Element without the
need to add your own custom CSS. Each color option accepts either a valid HEX
code (e.g. `available: &quot;#FF0000&quot;`) or a browser-safe color name (e.g. `available: &quot;tomato&quot;`)

- `hairline` - gridlines. Defaults to `#D8D8D8`

- `primary` - button background color. Defaults to `#15B3D6`

- `available` - available slot background color. Defaults to `#E2FAC8`

- `availableHover` - available slot when hovered. Defaults to `available` darkened by 10%

- `availableActive` - available slot when active. Defaults to `available` darkened by 20%

- `unavailable` - unavailable slot background color. Defaults to `#FFFFFF`

- `unavailableHover` - unavailable slot when hovered. Defaults to `unavailable` darkened by 10%

- `unavailableActive` - unavailable slot when active. Defaults to `unavailable` darkened by 20%

##### `tzid` *(optional)*

The time zone that the Availability Viewer will be rendered in. Must be a known time zone
identifier from the [IANA Time Zone Database](https://www.iana.org/time-zones). If `tzid` is declared, the time zone is displayed in the footer of the Element. If an invalid `tzid` is provided, then the Element will use the system time zone from the user's browser and trigger a [`warn` notification](/developers/ui-elements/index.md).

By default, the Availability Viewer will render in the time zone of the user's browser.

Be aware, using the `tzid` option will cause the Availability Viewer to render in a timezone that may not match the timezone of the user's computer. Be sure to highlight this to the user.

### Styling
Cronofy UI Elements come with built-in CSS that control their layout (as well as
adding a generic theme with placeholder colors and spacing). You can specify any
style rule you like in your own stylesheet.

To be sure to avoid specificity issues with CSS, make sure any custom selectors
you add are preceded by `.PREFIX`. For example, if your prefix is `ABC`, you
would target the button styles with this selector:

```css
.ABC .ABC__button {
    /* your button styles go here */
}
```

#### Element classes
`PREFIX` default is `AvailabilityViewer`.

- `{PREFIX}__body`

- `{PREFIX}__button`

- `{PREFIX}__column-body`

- `{PREFIX}__column-body--empty`

- `{PREFIX}__column-header`

- `{PREFIX}__column-header__day`

- `{PREFIX}__column-header__day`

- `{PREFIX}__column-header__day`

- `{PREFIX}__column-header__day`

- `{PREFIX}__column-header__day`

- `{PREFIX}__column-header__day`

- `{PREFIX}__column-header__day`

- `{PREFIX}__column-header__day`

- `{PREFIX}__column-header__ordinal`

- `{PREFIX}__column-message`

- `{PREFIX}__day-headers`

- `{PREFIX}__error`

- `{PREFIX}__error-icon`

- `{PREFIX}__error-text`

- `{PREFIX}__example`

- `{PREFIX}__footer`

- `{PREFIX}__grid`

- `{PREFIX}__grid-columns`

- `{PREFIX}__grid-column`

- `{PREFIX}__hover-positioner`

- `{PREFIX}__hover-positioner--main`

- `{PREFIX}__hover-positioner--tooltip`

- `{PREFIX}__hover-slot`

- `{PREFIX}__hover-slot--available`

- `{PREFIX}__hover-slot--unavailable`

- `{PREFIX}__icon`

- `{PREFIX}__legend`

- `{PREFIX}__legend-item`

- `{PREFIX}__legend-label`

- `{PREFIX}__loading`

- `{PREFIX}__loading-icon`

- `{PREFIX}__loading-text`

- `{PREFIX}__month-label`

- `{PREFIX}__month-labels`

- `{PREFIX}__navigation`

- `{PREFIX}__preloading`

- `{PREFIX}__preloading-icon`

- `{PREFIX}__preloading-text`

- `{PREFIX}__selected-slot`

- `{PREFIX}__selected-slot__button`

- `{PREFIX}__selection-mask`

- `{PREFIX}__selection-positioner`

- `{PREFIX}__slot-background`

- `{PREFIX}__slot-background--available`

- `{PREFIX}__slot-background--unavailable`

- `{PREFIX}__slot-tooltip`

- `{PREFIX}__slot-tooltip-background`

- `{PREFIX}__slot-tooltip-label`

- `{PREFIX}__tick-mark`

- `{PREFIX}__timeline`

- `{PREFIX}__timeline--hour`

- `{PREFIX}__timelines`

- `{PREFIX}__timezone`

- `{PREFIX}__time-label`

- `{PREFIX}__time-labels`

- `{PREFIX}__time-select__trigger`

- `{PREFIX}__time-select__trigger-icon`

- `{PREFIX}__time-text`

- `{PREFIX}__tooltip-positioner`

- `{PREFIX}__tooltip-positioner--available`

- `{PREFIX}__tooltip-positioner--unavailable`

- `{PREFIX}__week`

### Element methods
##### `refresh()`

From time to time you may wish to reload the AvailabilityViewer UI Element on the page. You can do this with the `AvailabilityViewer.refresh()` method:

```js
// Load AvailabilityViewer Element:
const AvailabilityViewer = CronofyElements.AvailabilityViewer(optionsObject);

// Refresh the AvailabilityViewer Element:
AvailabilityViewer.refresh();
```

> **INFO:** Being able to refresh a UI Element is useful in cases where your availability may have changed behind the scenes. UI Elements gather their availability data when they are first loaded, so unless they are refreshed they will not be aware of any changes to availability.

##### `update()`

Should you need to update the `options` for any Element, you can reload them with the `.update()` method (this requires you to have saved your Element instance to a variable beforehand):

```js
// Load AvailabilityViewer Element:
const AvailabilityViewer = CronofyElements.AvailabilityViewer(optionsObject);

// Update the AvailabilityViewer Element with new options:
AvailabilityViewer.update(newOptions);
```

When updating, you do not need to redeclare *all* the options; you just need to add the ones you want to update.

**Note:** The `AvailabilityViewer.update()` method must be called with an options object, otherwise a [warning-level log notification](/developers/ui-elements/index.md) will be fired.

##### `navigation`

There are several functions exposed that can be used to navigate the AvailabilityViewer programmatically.

##### `navigate.next()`

```js
// Load AvailabilityViewer Element:
const AvailabilityViewer = CronofyElements.AvailabilityViewer(optionsObject);

// Invoke next page
AvailabilityViewer.navigate.next();
```

**Note:** Listening to the `hasNext` attribute on the `&quot;displayed_dates_changed&quot;` notification type would give you an indication of whether this button is active or not.

##### `navigate.prev()`

```js
// Load AvailabilityViewer Element:
const AvailabilityViewer = CronofyElements.AvailabilityViewer(optionsObject);


// Invoke prev page
AvailabilityViewer.navigate.prev();
```

**Note:** Listening to the `hasPrev` attribute on the `&quot;displayed_dates_changed&quot;` notification type would give you an indication of whether this button is active or not.

> **INFO:** If you want to remove the buttons on the AvailabilityViewer, you can do this through styling. Add `.{PREFIX}__navigation { display: none }` to your CSS (replacing `{PREFIX}` with your elements prefix value) to hide the built-in navigation.



---
[Read in HTML](/developers/ui-elements/availability-viewer/)