Elements
Every part of the booking widget is a custom element whose name starts with mellow-. This page lists each one. The tables of attributes and values come from the widget's own types, widget/types/elements.d.ts, when the site is built, so they always match the script.
Rules for every element
- The page's own DOM. An element draws into the page, not into a shadow root. The site's CSS thus reaches every part.
isolateon<mellow-booking>is the one exception: see Look. - Default content, or your own. An element with no child elements draws its default content. An element with child elements draws nothing of its own: it binds the children it finds. Thus
<mellow-search></mellow-search>is a whole search form, and<mellow-search>around your own form gives your form Mellow's behaviour. - State as attributes. An element shows its state as
data-*attributes, such asdata-state,data-selected,data-disabled,data-loading,data-invalidanddata-empty. No element sets a class or an inline style. Style these attributes in your CSS. - Native controls. The default content uses
<button>,<select>,<input>,<fieldset>and<legend>. The calendar follows the ARIA grid pattern. The words come in English, Icelandic, German, French, Spanish and Italian. - One store.
<mellow-booking>owns the store of one booking. Every element inside reads it. A<mellow-search>that stands alone owns its own store. - Strings only. Every setting is a string attribute. Thus a server render, a WordPress shortcode and plain HTML set them the same way. An attribute with "no value" in the tables is on when it is there, such as
<mellow-booking isolate>. - Your own inputs. Inside the search and the driver form, an
input, aselector atextareawith a name the widget knows binds to the store.
Scopes
<mellow-value> and <mellow-price> show one field of the nearest scope above them. A scope is a car type, an insurance option, a product, a feature, a quote line or the confirmation. Outside every scope they read the order itself:
- Fields: the chosen car type's fields,
pickupAt,returnAt,pickupLocation,returnLocation,days,customer.firstName,referenceandcode. - Prices:
payNow,total,payOnArrival,perDay,taxanddepositof the order's quote.
Loading
While a read runs, the element waiting for it says so: data-loading and aria-busy="true" on <mellow-search> (the locations and their hours), <mellow-car-types> (the offers), <mellow-insurance> and <mellow-products> (the car type's products), and <mellow-summary> and <mellow-lines> (the quote). The step the address asks for shows at once. In the default content, and in a list with a template, skeletons stand in the place of what comes, in its shape: each is [part=skeleton] with data-kind (car-type, option, product or line), made of [part=bone-picture], [part=bone-line], [part=bone-short], [part=bone-price] and [part=bone-button]. A re-quote keeps the last numbers in the summary. <mellow-next> stays disabled while the offers, the products or a quote load.
Templates
A list element repeats its first <template> child for each item: <mellow-car-types>, <mellow-features>, <mellow-products>, <mellow-lines> and <mellow-progress>. Without a template it draws its default item. A list with a template draws the items only: <mellow-add-ons> and <mellow-products> then leave out their heading.
Code
The root and the flow
<mellow-booking>
The root. It makes the store, reads the order from the page's address, and keeps the step in the address, so the browser's Back button works. With no child elements it draws the whole flow: the step list, the currency picker, every step, the errors, Back and Next, and the summary beside the steps.
| Attribute | Values | Meaning |
|---|---|---|
rental (required) | text | The rental's slug. |
auth (required) | text | The widget's browser key, pk_live_… or pk_test_…. |
key | text | The old name of auth. Plain HTML only: React and Vue never pass key on. |
locale | text | en, is, de, fr, es or it. The page's lang by default. |
preset | none, plain | plain by default: the Plain stylesheet in the rental's colours. none loads no CSS. |
steps | text | The steps in order, space-separated, from search car-type insurance extras driver pay done. Leave one out to skip it, such as extras. The insurance step and the extras step also drop out by themselves when the chosen car type has nothing for them. |
paths | text | One page for each step, such as car-type=/book insurance=/book/insurance driver=/book/details. Without it every step is on this page. See Pages and paths. |
url-state | query, none | query (the default) keeps the step and the order in the address. none keeps them in memory. |
pay | embedded, redirect | embedded (the default) draws the processor's card form inside <mellow-pay>. redirect sends the customer to the processor's own page. |
return-url | text | Where the processor's page sends the customer back after pay="redirect". The pay step's page by default. |
terms | text | The rental's terms page. With it, the driver step asks the customer to accept them. |
isolate | no value: on when present | Draws the default flow into a shadow root, for a site whose theme CSS leaks in. Your own child elements are then left out. Only the tokens and ::part() style it. The embedded Rapyd form does not work under isolate yet. |
State: data-step (the current step), data-loading and aria-busy while a read is open, and data-narrow while the summary has no room beside the steps.
Where it is narrow, the default flow shows the total in a bar at the bottom of the screen in place of the summary under the steps. [part=nav], the row of Back and Next, sticks to the bottom and holds [part=total], a button with the total and "Tax included", and Next. A press on the total opens the whole summary in [part=sheet], a dialog from the bottom with a <mellow-summary> of its own and [part=close]. Back stands above the step. [part=main] carries data-narrow too, and [part=nav] has data-empty until a car type is chosen. Your own child elements get none of this.
After a step change, the new step's first heading takes the focus with no visible ring, so a screen reader starts there.
<mellow-step>
Shows its children only while the store's step is one of the names in when. when="extras driver" puts two steps on one screen. State: data-state is active or inactive, and the element has hidden while it is inactive.
| Attribute | Values | Meaning |
|---|---|---|
when (required) | text | One or more step names, space-separated. |
<mellow-progress>
A list of the steps, without done. Each item has data-step and data-state: done, current or todo. A done step is a button back to it. A <template> child sets each item, with <mellow-value of="name"> and <mellow-value of="number">, and any <button> in it goes to that step.
<mellow-back>
A button one step back. It is hidden on the first step and on done. Your own <button> inside takes the behaviour. State: data-hidden.
<mellow-next>
A button one step on. It is hidden on the search, pay and done steps: the search has its own button, and Pay is the last move. It has data-disabled while the step is not complete, and a press then shows what is missing in <mellow-error>. Your own <button> inside takes the behaviour. State: data-hidden, data-disabled.
<mellow-error>
The last refusal, as text in the customer's language, such as "No car of that type is free for those days." It is empty, with data-empty, while there is none. data-code holds the API's code, such as none_free. A <mellow-error> with no for leaves out the parts that have their own <mellow-error for="…"> on the page.
| Attribute | Values | Meaning |
|---|---|---|
for | text | The parts to show, space-separated: a step name, coupon, quote, pay or offers. |
The search
<mellow-search>
The search form. It keeps a draft while the customer fills it, and sends the search on submit:
- Inside
<mellow-booking>, it sets the store's search and moves to the car types. - Alone, with
action, it sends the browser toactionwith the search in the address. Put<mellow-booking>on that page. This is the shape of a search box on the home page.
An empty search starts filled in: the first pickup location, pickup 7 days from today and return 4 days later (or the rental's minimum stay), each on the first day the location is open, at 12:00 or the nearest open time. A search in the address, or a value in your own box, wins. The customer still presses Search.
Your own inputs inside bind by name: pickup, return, otherReturn, pickupAt and returnAt (as datetime-local), or pickupDate, pickupTime, returnDate and returnTime, then driverAge and coupon. An empty <select> of yours gets the options. State: data-complete once a location, both dates and both times are set, and data-other-return while the return goes to another location.
| Attribute | Values | Meaning |
|---|---|---|
rental | text | The rental's slug. Only when the search stands alone, outside <mellow-booking>. |
auth | text | The widget's browser key. Only when the search stands alone. |
key | text | The old name of auth, for plain HTML. Only when the search stands alone. |
locale | text | As on the root. Only when the search stands alone. |
preset | none, plain | As on the root. Only when the search stands alone. |
action | text | The booking page the search sends the customer to. |
layout | row, stack | stack puts the fields under each other. row puts them side by side, and the calendar opens in a dialog. The DOM is the same: the preset reads the attribute. |
car-type | text | A car type's slug, id or code, for that car type's own page. Only when the search stands alone. The search then prices that car type and shows <mellow-book> in place of <mellow-submit>. |
The address it writes holds pickup, pickupAt, return, returnAt, driverAge, coupon and mref. Times are the rental's local time, written YYYY-MM-DDTHH:MM, as the API takes them.
<mellow-location>
The rental's locations that serve a pickup or a return, as a list to pick from. The default content is a button that opens the list under it, or above it when the room below is too short. The list follows the ARIA listbox pattern: the arrow keys, Home, End, Page Up and Page Down move, a typed letter jumps to a location, Enter and Space pick, Escape and Tab close, and the focus goes back to the button. A location closed on the chosen day has data-disabled on its option. While the return goes to the pickup location, for="return" has data-hidden. A rental with only one location for a side hides that side, with data-hidden, and the search takes the location. Your own <select> inside binds instead. State: data-empty when no location serves it, data-open while the list is open.
Default parts: [part=trigger] (the button) with [part=value] and [part=chevron], [part=popover] around [part=list], and [part=option] for each location. [part=trigger] has data-placeholder while nothing is picked. [part=popover] has data-side (bottom or top) and data-align (start or end). An option has data-selected, data-highlighted and data-disabled.
| Attribute | Values | Meaning |
|---|---|---|
for (required) | pickup, return | pickup or return. |
<mellow-location-detail>
A text box that shows only when the chosen location asks for more, such as "Which hotel?". The location's own question is the label. State: data-hidden while the location asks for nothing.
| Attribute | Values | Meaning |
|---|---|---|
for (required) | pickup, return | pickup or return. |
<mellow-other-return>
A checkbox: return to another location. It is off by default, and the return location then follows the pickup. Ticked, the return location shows and asks for its pick. Your own checkbox inside, or one named otherReturn in the search, binds instead. State: data-selected while ticked, and data-hidden when fewer than two locations take returns.
<mellow-dates>
A range calendar. The customer picks the dates and never types them. One day takes the Tab key. The arrow keys move a day or a week, Home and End go to the ends of the week, Page Up and Page Down move a month, and Enter and Space pick. A picked day gets 10:00, or the nearest time the location is open. The rental's minimum stay blocks a return that is too early. State: data-state is empty, picking-return or complete.
| Attribute | Values | Meaning |
|---|---|---|
months | text | How many months show side by side, 1 to 3. 1 by default. |
mode | inline, popover | inline (the default) draws the calendar in the page. popover draws a button that opens it in a <dialog>. layout="row" on the search sets popover. |
Default parts: [part=head], [part=hint], and for popover also [part=label], [part=open] and [part=close]. For a calendar of your own, put these parts inside:
<mellow-month>
One month as a <table role="grid"> of <mellow-day> elements, with its name in [part=month-name], a heading by its role. State: data-month, such as 2027-06.
| Attribute | Values | Meaning |
|---|---|---|
offset | text | The month after the first one shown, counted from 0. offset="1" is the second month. |
<mellow-day>
One day, around its <button>. <mellow-month> makes these. data-state on the element is a space-separated list of start, end, in-range, selectable, closed (the location is closed), blocked (before the lead time, or past the longest stay) and today. Style it with [data-state~=start].
| Attribute | Values | Meaning |
|---|---|---|
date | text | The day, YYYY-MM-DD. <mellow-month> sets it. |
<mellow-month-prev>
A button to the month before. State: data-disabled on the current month.
<mellow-month-next>
A button to the month after.
<mellow-time>
The times the location is open on the chosen day, step minutes apart. A closed time and a lunch close are left out. The default content is a button with the time that opens one of two pickers:
- A wide screen: a popover with a grid of the open hours, and a row of the open minutes of the picked hour. A press on an hour keeps the minutes. A press on the minutes closes it. The arrow keys move in the grid, Home and End go to its ends, digits jump to an hour, and Escape closes.
- A phone (a coarse pointer, or a screen under 40rem): a sheet from the bottom with two wheels, hours and minutes, that snap as they turn. The time follows the wheels. Each wheel is a listbox that the arrow keys turn. Done or Escape closes it.
Your own <select> inside binds instead and gets the open times. State: data-empty when the location is closed that day, data-open while a picker is open.
Default parts: [part=trigger] with [part=value] and [part=chevron]; [part=popover] with [part=hours] and [part=minutes], of [part=hour] and [part=minute] buttons; [part=sheet] (a <dialog>) with [part=sheet-head], [part=sheet-title], [part=done], [part=wheels], [part=wheel] and [part=wheel-item]. An hour, a minute and a wheel item have data-selected.
| Attribute | Values | Meaning |
|---|---|---|
for (required) | pickup, return | pickup or return. |
step | text | The minutes between two times. 30 by default. |
<mellow-driver-age>
The driver's age, a list from the youngest age any car type takes, with the same button, parts and keys as <mellow-location>. Type "25" to jump to 25. It is optional. Your own <select> inside binds instead. With an age, a quote adds the young driver fee, and a car type the driver is too young for shows data-state="too-young".
<mellow-coupon>
A coupon box. Inside the search it goes with the search. Anywhere else it has an Apply button that prices the order with the coupon at once. Inside the search, Search checks the coupon against the car types' prices before it moves on. State: data-state is empty, checking, applied or refused. The default content says the result under the box in [part=status]: the coupon and what it gives, such as "SPRING10: 10% off", or the refusal, such as "This coupon does not exist." In your own markup the refusal shows in <mellow-error for="coupon">. A refused coupon changes no price, and it keeps the customer on the search until they fix it or clear it. A coupon that some car types take is applied, and each car type that took it shows the price before the coupon in <mellow-price of="before">.
<mellow-submit>
The search button. State: data-disabled until a location, both dates and both times are set.
<mellow-book>
On a car type's own page, in a search with car-type: the price of that car type for the search, and Book. It asks for the price by itself once a location, both dates and both times are set, and again after each change. Book opens action with the search and the car type chosen, on the insurance step. When the car type cannot be booked, it says why, such as "Not free on these dates", and See other campers (or cars) opens action on the car type step for the same search. State: data-state is empty until the search is complete, then loading, free, sold-out, unavailable or too-young, and data-loading while the price comes.
Default parts: [part=price] with [part=amount] and [part=days], [part=status] (the hint, the wait or the reason), [part=book] and [part=others]. In your own markup inside, a button named book books and one named others opens the other car types.
Car types
<mellow-car-types>
The car types for the search, each with its price, from one quote request for all of them. A car type that cannot be booked stays in the list with its reason in data-state on its <mellow-car-type>. The first <template> child is each item. Without one, each item is the default card: the first picture, the name, one line of facts, the pay-now total and the price a day, then Details and Choose side by side. The picture and Details both open the car type's details (<mellow-details>). State: data-empty when nothing is left to show, data-loading while the prices come.
| Attribute | Values | Meaning |
|---|---|---|
sort | price, name, seats, rental | price (the default), name, seats, or rental for the rental's own order. |
hide-unavailable | no value: on when present | Leaves out every car type that cannot be booked. |
<mellow-car-type>
One car type's scope. The list makes one for each item. Place one yourself with id to show one car type on its own page: beside a search with car-type, it reads that search, and inside a <mellow-booking> that starts without the car type step, it chooses itself. State: data-selected, data-state (free, sold-out, unavailable or too-young), data-kind (car or camper), data-transmission, data-drive and data-fuel. Thus [data-kind=camper] styles campers apart.
| Attribute | Values | Meaning |
|---|---|---|
id | text | The car type's id, slug or code, for a car type placed on its own page. The list sets nothing here. |
Fields of a car type for <mellow-value>: name, description, make, model, code, slug, acriss, seats, doors, largeBags, smallBags, transmission, drive, fuel, kind, sleeps, minDriverAge, includedKmPerDay, yearFrom, fRoads, guaranteedModel and customFields.<key>. Words such as manual come in the customer's language.
<mellow-value>
One field of the nearest scope, as bare text with no markup of its own. State: data-empty when the field is empty.
| Attribute | Values | Meaning |
|---|---|---|
of (required) | text | The field's name, such as name, seats or customFields.beds. |
<mellow-price>
One price of the nearest scope, in the customer's locale, and in the currency the customer picked. State: data-empty when there is none, data-loading while the price comes.
| Attribute | Values | Meaning |
|---|---|---|
of | text | payNow (the default): what the customer pays with the booking. total: the whole total, fees at the desk included. payOnArrival: the fees paid at the desk, empty when 0. perDay: payNow over the days. tax: the tax in the total. deposit: the deposit. Inside a car type: before, the price before the coupon, empty when no coupon took anything off. Inside an option: optionDelta ("Included", "Refused", or what it adds) and optionTotal. Inside <mellow-line>: line. Inside <mellow-product>: unit, the product's own price, such as "1,500 kr. a day, at most 7 days". |
charge | no value: on when present | Always in the rental's currency, whatever the currency picker shows: what the card is charged. |
<mellow-image>
One of the car type's pictures as an <img>, with alt from the name and loading="lazy". Inside a <mellow-product> or a <mellow-option> it is the product's one picture instead, and index does nothing. The <img> has a srcset of the picture's widths, so the browser loads the smallest one that fills the space. State: data-empty when there is no such picture.
| Attribute | Values | Meaning |
|---|---|---|
index | text | Which picture, counted from 0. 0 by default. |
sizes | text | The width the picture takes on the page, as the sizes of an <img>, such as (max-width: 40rem) 100vw, 20rem. auto, 100vw by default: the browser measures a lazy picture itself. |
<mellow-gallery>
Every picture of the car type in one strip that swipes on a phone, with Previous and Next buttons over it and a count, such as 2 / 4. The pictures come in the rental's order, and a picture tagged floor_plan comes last. Parts: [part=track] (the strip of <img>), [part=prev], [part=next] and [part=count]. Each <img> has data-tag (exterior, interior or floor_plan) when the rental tagged it: Plain shows a floor plan whole, never cut. State: data-index (from 0), data-empty.
<mellow-features>
The car type's features that are on, in Mellow's groups. Each item is a <mellow-feature>. A <template> child sets the item's markup. State: data-empty.
| Attribute | Values | Meaning |
|---|---|---|
group | text | One group only: technology, utilities, camping, heating_cooling, kitchen or sleeping. Every group by default. |
<mellow-feature>
One feature's scope. Fields: name, group, count, size and label (the name with the count and the size, such as "2 × Duvet, 140 × 200 cm"). State: data-group.
<mellow-details>
The details of the car type of its scope, in a native modal <dialog>: the pictures, the description, the features in their groups, the name with "or similar" when the model is not guaranteed, the price for the trip and a day, Choose (or the car type's state, such as Sold out), and the specs. With no child elements it draws a Details button, [part=open]. With child elements, a press on any button or link among them opens it, such as <mellow-details><button>More</button></mellow-details> or a picture inside a button. A <template> child sets the dialog's body, and the widget's parts inside it read the same car type. The body is drawn at each open and removed at close.
The dialog traps the focus, Escape or Close ([part=close]) shuts it, and the focus goes back to the button that opened it. Choose inside it chooses and closes it. It sends mellow-details when it opens. Parts of the dialog: [part=dialog], [part=head], [part=close], [part=body], then in the default body [part=main] (pictures, description, features), [part=side], [part=title], [part=similar], [part=buy] (the price and Choose), [part=price], [part=days] and [part=features], with one <section data-group> for each group. With Plain, a phone gets a sheet over the whole screen that slides up, with Choose fixed at the bottom. State: data-open.
Code
<mellow-specs>
The car type's specs as a <dl>, one <div data-spec> for each spec it has: sleeps (a camper), seats, doors, bags, transmission, drive, fuel, year (such as "2022 or newer"), km (such as "250 km a day", or "Unlimited"), age (the youngest driver) and f-roads (only where the rental's country has them). State: data-empty.
<mellow-description>
The car type's description from the rental's Markdown: paragraphs, lists, bold, italic and https links, drawn as elements, never as HTML. State: data-empty.
<mellow-choose>
A button that chooses the car type of its scope and moves on. A car type that cannot be booked shows why in [part=status] in its place: Sold out, Not available, or Driver too young. State: data-disabled, data-loading.
<mellow-payment-terms>
The payment terms the rental sells for the car type of its scope, as a radio list: each term's title, its difference from the cheapest term ("Included" on the cheapest), and one line on what it allows under the picked one. Picking a term prices the order on it, and the hold and the booking take it. The car type's details show it under Choose. A rental that sells one term shows nothing. Each row is a <label part="term"> with data-selected, holding [part=title], [part=difference] and [part=summary]. State: data-empty. See Payment terms in the API guide.
<mellow-filter>
Checkboxes over the list, one for each value the list holds of one field. State: data-empty when the list holds fewer than two values.
| Attribute | Values | Meaning |
|---|---|---|
field (required) | kind, transmission, drive, fuel, seats | The field to filter on. |
<mellow-sort>
A <select> that sorts the list by price, name, seats or the rental's own order.
Insurance
The insurance step sells what the rental sells, in the shape the rental sells it. A level (such as Basic, Premium, Platinum) keeps the cover of each level below it, and a booking holds one. An add-on cover goes beside any level. A package is one priced line of other products. An included cover is on every booking.
<mellow-insurance>
The step's container. With no child elements it picks its layout from what the rental sells for the chosen car type. State: data-shape:
data-shape | The rental sells | The default layout |
|---|---|---|
levels | Levels, with or without packages | <mellow-compare>, then <mellow-add-ons> below |
packages | Packages only | <mellow-compare> with one column for each package |
add-ons | Add-on covers only | <mellow-add-ons> alone, as a list of switches |
included | Only included covers | <mellow-liability> alone. The step needs no click |
none | Nothing | The step drops out |
With levels or packages, the default layout puts [part=intro] above the compare: "What you pay at most if something happens". Under the compare, when the included level may be refused, it puts [part=no-cover]: one tick box, "Rent with no cover". Ticked (data-selected), [part=result] says in place what that leaves, each only when true: nothing is covered, the deposit, and that the price does not change. [part=keep], "Keep cover", takes the cover back. The included level's option then has data-declined and says "Refused" in place of "Included".
<mellow-compare>
The options side by side: each level, and each package that holds a cover. It is a radio group, as a booking holds one level. The included level is the first pick. Each <mellow-option> has the same rows in the same order, so a table on a wide screen and stacked cards on a phone come from one DOM. State: data-empty, data-loading.
| Attribute | Values | Meaning |
|---|---|---|
perils | text | The perils that make the rows, in order, such as collision theft gravel sand_ash. By default the perils whose excess differs between the options. |
recommend | text | The code of the option to mark as the pick, such as PREMIUM. |
price | delta, total | delta (the default) shows what each option adds to the price. total shows the whole pay-now with that option. |
Perils: collision, theft, glass, tyres, gravel, sand_ash, scratches, undercarriage, water, interior, keys and other.
<mellow-option>
One level or one package: its scope. Fields: name, description, code, level and includes (the names of what it holds). State: data-selected, data-included (on the booking at no charge), data-recommended, data-unavailable (the driver's age needs a higher level, and the badge says so), data-kind (level or package), data-level (1 to 3) and data-declined (the included level, refused: no level is then picked). Default parts: [part=badge] and [part=includes].
| Attribute | Values | Meaning |
|---|---|---|
id | text | The product's id or code, for an option you place yourself. The compare sets nothing here. |
<mellow-pick>
The option's radio button. Picking the included level takes the picked one off. Picking any option ends a refusal of the included level. State: data-selected.
<mellow-coverage>
The excess left for each peril, as a <dl>: under an option, its quote's liability (the levels below counted in), and under an add-on cover, the cover's own. Each row has data-peril and data-state: full (no excess: "Covered in full"), reduced (an amount) or none (not covered). State: data-empty.
Under an option the list has [part=head]: "If this happens" and "You pay at most", the words of the rental agreement. A row that says the same as the option before it (for the first option: not covered) has data-same. With data-fold (some rows are the same, some are not), Plain shows only the other rows where the options stack as cards, and [part=more], "Show all 11" with the real count, opens the rest (data-open). The table on a wide step shows every row.
<mellow-add-ons>
The add-on covers of the chosen car type, each a <mellow-product> row with its price, its Add button and its <mellow-coverage>. One that the picked option already holds shows data-included and "Included in Premium" in place of the button. State: data-empty.
<mellow-liability>
What the booking leaves the customer to pay at most, after every cover on it, the damage handling and the deposit. It changes as the customer picks. Fields: deposit, handling (the cost for each damage on top of the excess, when a cover names one), excess.<peril> and included. State: data-empty, data-loading.
Extras
<mellow-products>
The products of the extras step for the chosen car type. A <template> child sets each item. The package ladder comes first, low to high: the customer holds one package level at most, and adding one takes the other off. State: data-empty.
| Attribute | Values | Meaning |
|---|---|---|
kind | extra, package | extra gives the extras, package the packages with no cover. Both by default. |
<mellow-product>
One product's scope. Fields: name, description, code, maxQuantity, extraDrivers and includes (a package's products, by name). The default product is one row: a <mellow-image> (a 44 px square of its picture, an empty square when it has none), [part=text] with [part=name], [part=description] (one line) and [part=includes], then <mellow-price of="unit"> and <mellow-quantity>. State: data-selected, data-included (in a level or a package the customer took), data-default (on every booking), data-declined, data-kind and data-level (a package on the ladder).
| Attribute | Values | Meaning |
|---|---|---|
id | text | The product's id or code, for a product you place yourself. The lists set nothing here. |
<mellow-quantity>
The product's control. The default content is an Add button ([part=add]). For a product taken once, or a package on the ladder, it turns to "Added ✓" (aria-pressed="true"), and a second press removes the product. For a product with maxQuantity above 1 it turns to a stepper ([part=stepper]: −, [part=count], +), and 0 brings back Add. A product on every booking, or in a package the customer took, shows [part=included] in place of the control. Your own markup binds an <input> (a checkbox, a radio or a number box) and two buttons, one less and one more. State: data-value, data-included.
<mellow-decline>
A checkbox to refuse a product that is on every booking and may be refused. It is hidden for any other product. State: data-selected, data-hidden. The default option holds none: the included level is refused by "Rent with no cover" under the compare. Refusing an included level takes a picked level off, so the booking holds no level.
The driver
<mellow-driver>
The customer form. With no child elements it holds every field the booking may take. Your own inputs with the same name bind instead. The details stay in the tab's sessionStorage, never in an address. State: data-invalid while a required field is empty.
name | Required | Meaning |
|---|---|---|
customer.firstName | yes | |
customer.lastName | yes | |
customer.email | yes | For the confirmation |
customer.phone | no | |
customer.country | no | A list of countries, empty at first |
flightNumber | no | Shown when the pickup is at an airport |
passengers | no | |
notes | no | |
customer.marketingOptIn | no | A checkbox, off by default |
pickupDetail | when asked | The location's own question |
returnDetail | when asked | The location's own question |
terms | with terms | The terms checkbox |
<mellow-field>
One field: a <label>, the control and an error text in [part=error]. State: data-invalid on a refusal, data-hidden when the field does not apply.
| Attribute | Values | Meaning |
|---|---|---|
name (required) | text | The field's name, from the table above. |
optional | no value: on when present | Makes customer.email optional. |
<mellow-terms>
The terms checkbox with a link to the rental's terms. It shows only when the root has terms, and then the customer must tick it before Pay. State: data-hidden, data-invalid.
Pay and done
<mellow-pay>
The last step. On Pay it does these things in order:
- It runs the bot check: Cloudflare Turnstile, in a small frame on Mellow's host, inside
[part=turnstile]. The frame has no height until Turnstile needs the customer, then it is 300 by 65 pixels. - It holds one car for the order, at a fixed total, for 15 minutes.
- It asks for the payment of the pay-now amount on the hold.
- With
pay="embedded"the processor's card form opens inside it. Withpay="redirect"the browser goes to the processor's page. - It waits until the processor's paid webhook makes the booking from the hold, and then moves to done.
No card data reaches the page's code or Mellow. A refusal, such as none_free when the last car went, shows in <mellow-error>. State: data-state is ready, booking (the hold), paying, paid or failed, and data-test with a test key. Default parts: [part=review], [part=secure], [part=pay], [part=estimate], [part=status], [part=processor], [part=turnstile], and for a test key [part=test] and [part=open-test].
The default content is a review before the payment. [part=review] has a row for each of these, and only when its data exists: [part=driver] (the name over the email, with [part=change], which goes back to the driver step), [part=term] (the payment term the price is on: its title over its one line on cancelling and refunds) and [part=deposit] ("Deposit at pickup" with its amount). [part=secure] says that the card goes in on the payment provider's secure page. The one amount is on [part=pay], the charge in the rental's currency. [part=estimate] shows under it while another currency is picked.
<mellow-confirmation>
The booking reference, the trip, and links to manage the booking and to check in online, on the rental's own address. Fields: reference, code, customer.firstName, pickupAt, returnAt, pickupLocation and returnLocation. State: data-state is waiting or booked, and data-test for a test booking, which shows its code (such as TEST-4F2A) and no links. Default parts: [part=thanks], [part=links].
<mellow-summary>
The live quote, beside any step from the car type on. It is empty, and hidden, until a car type is chosen. The default content stacks: [part=car-type], [part=similar] ("or similar", when the model is not guaranteed), [part=trip] ([part=pickup] and [part=return], each a [part=place] over a [part=when] such as "Thu 19 Nov · 10:00"), the lines, [part=totals] and [part=tax], [part=deposit] ("Deposit at pickup", when the quote holds one), then a <mellow-currency-note>. The totals show only [part=total], unless a fee is paid at pickup: then [part=pay-now] and [part=on-arrival] come above it. State: data-empty, data-loading.
<mellow-lines>
The quote's lines. A <template> child sets each line. State: data-empty.
<mellow-line>
One line of the quote: its scope. Fields: name, quantity, kind and detail (how the amount came about, such as "3 days × ISK 6,785", empty when no quantity or days apply), and <mellow-price of="line">. State: data-kind (vehicle, extra, insurance, fee, package, location_fee, one_way_fee or discount) and data-on-arrival. Default parts: [part=name], the price, then [part=detail] under the name.
Currency
<mellow-currency>
A <select> of the currencies the customer may see prices in, with a <mellow-currency-note>. The charge stays in the rental's currency. It may stand outside <mellow-booking>, such as in the site's header: it then reads the first <mellow-booking> or <mellow-search> on the page. Your own <select> inside binds instead. State: data-currency, data-converted (another currency than the rental's), and data-empty (fewer than two to pick from: the default content is then hidden). See Display currency.
| Attribute | Values | Meaning |
|---|---|---|
currencies | text | The codes to offer, space-separated, such as EUR USD NOK. The rental's currency always comes first. The widget's list in Mellow by default. |
value | text | The first pick while the customer has picked none, such as EUR. The rental's currency by default. |
<mellow-currency-note>
The note while prices show in another currency: "Prices in EUR are estimates. You pay in ISK." It is empty, with data-empty, and hidden while the rental's own currency shows.