Appearance
Appearance is set in the restaurant’s back office. The host page controls where the widget goes and how much room it has, and nothing else about how it looks.
That split is enforced by the DOM rather than by convention: the widget renders inside a shadow root, so host page CSS does not select into it.
Set in the back office
Section titled “Set in the back office”| Setting | Effect |
|---|---|
| Brand colour | Buttons, selected days, the active time slot. |
| Logo | Replaces the restaurant name in the header. |
| Restaurant header | Off hides the restaurant’s own name — for a group surface. |
| Inherit host typography | Off by default. On, the widget uses the host page’s font. |
The last three exist for groups: a hotel with eight restaurants can present one booking surface that reads as the group’s rather than as whichever restaurant the guest happened to land on.
The colour is a single brand colour, and the text drawn on it is computed for contrast rather than configured. A pale brand colour produces dark text on it, not white text nobody can read.
Style isolation
Section titled “Style isolation”The widget’s styles are adopted by its shadow root as a constructable stylesheet. Two consequences worth knowing:
- Host CSS does not reach the widget. A page-wide
button { … }rule, a CSS reset, or a framework’s utility classes have no effect inside it. - Widget CSS does not reach the host page. Nothing the widget ships can restyle the page it is embedded in.
Because the stylesheet is adopted through the CSSOM rather than injected as a
<style> element, a strict style-src on the host page does not block it. A
host with a strict Content-Security-Policy needs no style-src entry for the
widget.
One exception is worth knowing about: the brand colour is applied as an inline
style attribute. A host page whose policy sets style-src without
style-src-attr 'unsafe-inline' blocks that attribute, and the widget renders
in its default colour rather than the restaurant’s.
What still crosses the boundary
Section titled “What still crosses the boundary”Inherited CSS properties cross a shadow boundary — that is how inheritance works, and it is not something isolation prevents.
The widget’s own stylesheet sets what it needs, so this matters in one place:
font-family, when inherit host typography is on. It is off by default,
because a display face chosen for a hero banner applied to a booking form is the
one appearance setting that can make the widget unreadable, and a font the
restaurant did not choose is a worse default than one it did.
When it is on, the widget uses font-family: inherit rather than a font name
copied from the page. It therefore picks up whatever the host is actually
using, webfonts included.
Size and placement
Section titled “Size and placement”inline
Section titled “inline”The widget fills its container up to 440px, is centred within it, and does not shrink below 320px. A container narrower than that will be overflowed rather than obeyed.
Below a 640px viewport the caps are dropped: the widget fills the width, loses its rounded corners and shadow, and takes at least a full viewport height, so a booking on a phone reads as a page rather than as a card.
popover and sticky
Section titled “popover and sticky”Both mount at the end of <body>, in their own stacking context, above
everything on the page — the popover portal at the maximum z-index, the sticky
button just below it. The popover is capped at 420px and goes full-bleed on
phones.
position (or data-position) anchors the sticky button and the popover:
bottom-right by default, out of six anchors — three across the top, three
across the bottom. Below 640px the anchor is ignored and the popover becomes a
full-screen sheet.
The trigger element in popover mode is the host’s own — [data-service-widget-open]
is a hook, not a style. Nothing is applied to it.
The payment overlay
Section titled “The payment overlay”When a booking requires a card guarantee, the payment step renders in an overlay at the body level rather than inside the widget: Stripe’s payment element cannot mount inside a shadow root.
It brings its own design tokens, scoped to the overlay’s own container, so embedding the widget never changes how the host page looks — not even while the overlay is open.
One theme
Section titled “One theme”The widget renders in a single light theme. It does not follow
prefers-color-scheme, and there is no dark variant to opt into.