Skip to content

Advanced Options

For power users who want full control over the calendar widget beyond what the dashboard and the embed parameters offer.

CSS custom property overrides

You can override any visual property in the view editor. Open the view, find Theme, expand Advanced CSS Overrides, and enter a JSON object. Overrides are saved with the view and apply to every embed of it. Choose the palette with the palette buttons above the box; the box holds only the overrides.

Each key in the object is converted to a CSS custom property.

The conversion follows a camelCase to --already-kebab-case pattern:

Theme key CSS custom property Controls
primary --already-primary Accent: active tab, buttons, links, date badges
primaryText --already-primary-text Text drawn on top of primary
background --already-background The calendar's own ground
surface --already-surface Cards, panels, and the layer above the ground
text --already-text Primary text
textSecondary --already-text-secondary Dates, locations, supporting text
border --already-border Base the two below inherit from
borderControl --already-border-control Tab strip, nav bars, buttons, dropdowns
borderGrid --already-border-grid Weekday header, week columns, event rows
highlight --already-highlight Today, hover, and selected states
error --already-error Error card accent
fontFamily --already-font-family The whole widget's type stack
fontSizeSm --already-font-size-sm Supporting text
fontSizeBase --already-font-size-base Body text
fontSizeLg --already-font-size-lg Event titles
fontWeightNormal --already-font-weight-normal Body weight
fontWeightBold --already-font-weight-bold Title weight
radius --already-radius Corner radius on cards and buttons
radiusSm --already-radius-sm Corner radius on small elements
shadow --already-shadow Card elevation
shadowHover --already-shadow-hover Card elevation on hover
spacing --already-spacing Base spacing unit

Values accept the usual CSS forms for each property: transparent, rgba(...), none, 0, hex, and hsl(...).

Any color, font or shadow override turns off matching your site. Layout and size keys do not.

calc(), clamp() and var() are not accepted. Theme values are also rendered into a stylesheet server-side, where an arbitrary value would be an injection risk, so each one is validated against the grammar for its type. A value that fails validation is dropped and the palette default applies.

Making the calendar match your site

The default palettes are starting points. Three overrides do most of the work of making the widget stop looking like an embed:

A flat, high-contrast site

For a site with a hard-edged, poster-like design: a cream page, near-black text, a strong accent, and no elevation anywhere.

{
  "background": "#f6eadd",
  "surface": "#f6eadd",
  "text": "#1a1a1a",
  "textSecondary": "#5c5147",
  "primary": "#a54734",
  "border": "#1a1a1a",
  "radius": "0",
  "shadow": "none"
}

Setting surface equal to background removes the card layer, so events sit directly on the page instead of on tiles.

A photographic background

With the script tag embed and no colors chosen, the calendar is already transparent and takes its text color from your page; see Matching your site. The theme below is for iframe embeds, or when you want to set the colors yourself.

If your calendar sits on top of an image, set background to transparent so the photograph shows through, and give surface enough opacity to keep text readable over whatever is behind it.

{
  "background": "transparent",
  "surface": "rgba(255, 255, 255, 0.92)",
  "text": "#1a1a1a",
  "primary": "#de0086"
}

Check the contrast against the busiest part of your image, not the calmest.

Fonts

With Match site and the script tag, the calendar loads your page's font when it comes from Google Fonts or Bunny Fonts. Setting fontFamily turns Match site off, so the rest of this section applies once you set it. Otherwise the calendar renders in an iframe and does not inherit fonts your page loads. Naming your brand face in fontFamily alone gets the visitor's fallback. It will look correct to you if that font is installed on your machine, which is what makes this easy to miss.

Use a system stack if an exact match is not essential. Nothing loads, text renders immediately, and no request leaves the page:

{ "fontFamily": "system-ui, -apple-system, sans-serif" }
{ "fontFamily": "Georgia, 'Times New Roman', serif" }

Or load your brand font with fontUrl. Name the family first in fontFamily and point fontUrl at the file:

{
  "fontFamily": "Figtree, system-ui, sans-serif",
  "fontUrl": "https://fonts.gstatic.com/s/figtree/v5/_Xm.woff2"
}

The first family names the loaded face. Everything after it is the fallback, used while the font downloads and if it fails.

fontUrl must be https, must end in .woff2, .woff, .ttf or .otf, and must be served by one of:

Provider Host
Google Fonts fonts.gstatic.com
Bunny Fonts fonts.bunny.net

Anything else is rejected and the fontFamily stack is used instead, so a bad URL falls back to a system font rather than to invisible text.

The list is short on purpose. Loading a font means every visitor's browser requests it from that host, which reveals their IP to whoever you named, so the embed permits only providers already handling that traffic at scale. If you self-host elsewhere and need it supported, ask and we will add it.

Hierarchy in borders

border sets every rule at once. If your site has a defined hierarchy, split it: borderControl covers the chrome (tab strip, nav, buttons) and borderGrid covers the calendar's internal lines. Both default to border, so setting only border behaves as it always has.

{
  "border": "#1a1a1a",
  "borderGrid": "rgba(26, 26, 26, 0.12)"
}

A strong frame with quiet internal lines, rather than every line equally heavy.

Unknown keys are ignored silently

A key that is not one of the above becomes a CSS custom property nothing reads, so a typo like backgroundColor has no effect and reports no error. If an override seems not to apply, check the spelling against the table first.

Sticky header options

The sticky header can be configured granularly as an object instead of a simple boolean:

{
  "header": true,
  "viewSelector": true,
  "tagFilter": false
}

Each key controls whether that UI element sticks to the top of the viewport as the visitor scrolls. Set the sticky URL parameter, or the data-sticky attribute on the script tag, to this object to pin specific elements while letting others scroll.

Auto-resize for iframe embeds

The calendar posts { type: 'already-events:resize', height }, with the height in pixels, to its parent window whenever its content height changes. The script tag listens for this message and resizes the iframe on its own. With a plain iframe, add a listener yourself. It must check that the message came from your iframe and from https://embed.already.events, and it must reject heights that are not finite positive numbers. The script tag also rejects heights above 50000 pixels.

const frame = document.querySelector('iframe[src^="https://embed.already.events/"]');

window.addEventListener('message', (event) => {
  if (event.source !== frame.contentWindow) return;
  if (event.origin !== 'https://embed.already.events') return;
  const data = event.data;
  if (!data || data.type !== 'already-events:resize') return;
  if (typeof data.height !== 'number' || !isFinite(data.height)) return;
  if (data.height <= 0 || data.height > 50000) return;
  frame.style.height = data.height + 'px';
});

If your iframe loads from your own subdomain, compare event.origin with that subdomain's origin instead.

Extending known platforms

These options apply when you run the open-source already-cal widget yourself. A hosted embed does not expose them.

The calendar recognizes URLs from 18+ platforms by default. You can extend the platform list using Already.DEFAULTS:

Already.init({
  el: '#calendar',
  google: { apiKey: '...', calendarId: '...' },
  knownPlatforms: [
    ...Already.DEFAULTS.knownPlatforms,
    { pattern: /your-site\.com/i, label: 'Visit Our Site' },
  ],
});

Already.DEFAULTS contains all the default configuration values. Spreading it into your config lets you extend rather than replace the built-in platform list.

Callbacks

These options apply when you run the open-source already-cal widget yourself. A hosted embed does not expose them.

You can register callback functions for event-driven behavior:

Data hooks

These options apply when you run the open-source already-cal widget yourself. A hosted embed does not expose them.

Transform or filter events before they're displayed:

These hooks run in the pipeline after built-in enrichment (directive extraction, image detection, etc.) and before rendering.