The point of this storefront
How this shop complies, requirement by requirement
Ideal Commerce is a reference implementation. It exists to show what an e-commerce site looks like when EU consumer law is treated as the design brief rather than as a compliance chore bolted on at the end. Every requirement below names the sentence in the Directive, the page on this site that satisfies it, and the file in the repository that implements it — because “we are compliant” is a claim, and this is the evidence.
This is not legal advice. It is a working demonstration written by engineers, and a real shop's obligations depend on where it is established, what it sells and to whom. Read it as a starting point and a set of worked examples, not as an opinion you can rely on.
The online withdrawal function
Directive (EU) 2023/2673, inserting Art. 11a into Directive 2011/83/EU
Applies from 19 June 2026. Every distance contract concluded through an online interface must offer a withdrawal function on that interface — prominently displayed, continuously available, labelled in the statutory wording, completed by a separate confirmation control, and followed by an acknowledgement on a durable medium carrying the declaration and the date and time it was submitted.
-
An online withdrawal function exists
ImplementedWhat the law requires
The trader must allow the consumer to withdraw ALSO by means of a withdrawal function on the online interface. An e-mail address, a downloadable PDF or a phone number is not a withdrawal function: the declaration must be submittable through the interface itself.
Art. 11a(1)
How this site does it
A dedicated page that takes the declaration and submits it. It records the declaration, stamps the submission instant and produces the acknowledgement — all without a server, which is the point: the obligation does not depend on having a backend.
src/pages/withdraw/index.astrosrc/lib/store.ts -
Labelled “withdraw from contract here”, legibly
ImplementedWhat the law requires
The function must carry the words “withdraw from contract here” or an equally unambiguous formulation, displayed in a legible form. “Returns”, “Contact us” and “My orders” are not unambiguous and fail even where the flow behind them works.
Art. 11a(1), second subparagraph
How this site does it
That exact wording is the label on every entry point — the footer band, the footer Help column, the customer-service hub, the orders list and each order page. It is rendered at body size or larger, at full contrast, as a control rather than as a line of prose.
The function itselfCustomer-service hub
src/components/Footer.astrosrc/pages/help/index.astrosrc/pages/order/index.astro -
Prominently displayed and easily accessible
ImplementedWhat the law requires
The function must be placed prominently on the online interface and be easy for the consumer to find and use. Hyperlinks leading to it are an acceptable way to achieve that (Recital 37). A link that exists only inside a transactional e-mail does not make the storefront prominent.
Art. 11a(1) read with Recital 37
How this site does it
It has its own band at the top of the footer of every page — above the link columns, not buried in them — plus a row in the Help column, a full-width card on the customer-service hub, a card on every order, and a button on every row of the order list. One click from anywhere on the site.
src/components/Footer.astro -
Continuously available throughout the withdrawal period
ImplementedWhat the law requires
Reachable at any time during the withdrawal period, without creating an account, logging in, passing a paywall or waiting for the trader to approve anything first.
Art. 11a(1), second subparagraph
How this site does it
The page is public and static. There is no account system on this site at all, so there is nothing to log into and nothing to gate it behind. It works with an order number typed in cold, and it works when the browser has never seen the order.
src/pages/withdraw/index.astro -
The consumer can provide or confirm their name
ImplementedWhat the law requires
The statement must let the consumer easily provide OR CONFIRM their name. Pre-filled values count — Recital 37 says a consumer who has already identified themselves should not have to state their identity again.
Art. 11a(2)(a) read with Recital 37
How this site does it
Arriving from an order link, the name is filled in from the contract and shown for confirmation. Arriving cold, it is typed. Both routes satisfy the paragraph; the first is the one Recital 37 asks for.
src/pages/withdraw/index.astro -
The consumer can provide or confirm the contract details
ImplementedWhat the law requires
The statement must let the consumer provide or confirm the details identifying the contract.
Art. 11a(2)(b)
How this site does it
Order number and order date, either typed or carried in the link from the order. Orders known to this browser are offered as one-tap buttons, and the matched order is read back in full — items, total, payment method, deadline — before anything is confirmed.
src/pages/withdraw/index.astro -
The consumer can provide or confirm the electronic means for the acknowledgement
ImplementedWhat the law requires
The statement must let the consumer provide or confirm the electronic means by which the acknowledgement of receipt will be sent.
Art. 11a(2)(c)
How this site does it
An e-mail field, pre-filled from the order where we have it, with an explicit note that the acknowledgement is also handed over on screen and as a downloadable file — so nothing depends on a message arriving.
src/pages/withdraw/index.astro -
A separate “confirm withdrawal” control completes the declaration
ImplementedWhat the law requires
The consumer must submit the statement by activating a confirmation function legibly marked with the words “confirm withdrawal” or an unambiguous equivalent. Its purpose (Recital 37) is to stop a consumer withdrawing unintentionally. “Send”, “OK” and “Submit” do not discharge it.
Art. 11a(3) read with Recital 37
How this site does it
One control, labelled exactly “Confirm withdrawal”, at 58px tall in the primary colour, and it is the only thing on the page that submits. The full declaration is shown immediately above it and updates live, so nobody confirms something they have not read.
src/pages/withdraw/index.astro -
An acknowledgement of receipt arrives without undue delay
ImplementedWhat the law requires
Once the confirmation function is activated, the trader sends the consumer an acknowledgement of receipt of the withdrawal on a durable medium, without undue delay.
Art. 11a(4)
How this site does it
Immediately, on the next screen — and as a self-contained HTML file the consumer downloads, stores, reopens and prints. A durable medium is one the consumer can keep unchanged and reproduce later; a downloaded file is exactly that. It stays available from the order page for good.
src/pages/withdraw/acknowledgement/index.astrosrc/lib/durable.ts -
The acknowledgement carries the content and the date AND time
ImplementedWhat the law requires
The acknowledgement must contain information about the content of the withdrawal declaration and about the date and time of its submission. A date alone is not enough.
Art. 11a(4)
How this site does it
The submission instant is captured once, when the confirmation control is activated, and printed to the second with its time zone — on screen and in the downloaded document. The declaration is repeated back verbatim in a quoted block, not summarised.
src/lib/durable.tssrc/lib/dates.ts -
Withdrawing is no more burdensome than ordering was
ImplementedWhat the law requires
The procedure for exercising the right of withdrawal must not be more burdensome than the procedure for concluding the contract. Recital 37 names being required to download an app as an example of what is forbidden.
Recitals 36 and 37
How this site does it
The checkout takes three steps; the withdrawal takes one screen and one button. No mandatory reason, no retention offer, no captcha, no identity check the checkout never asked for, no app, no phone call, no account. The reason field is optional and says so twice.
One screenCompare with the checkout
src/pages/withdraw/index.astro -
Pre-contractual information states the function exists and where it is
ImplementedWhat the law requires
The pre-contractual information must include, where applicable, information about the existence and the location of the withdrawal function referred to in Art. 11a. Annex I(A) instruction [3] gives the prescribed wording.
Art. 6(1)(h) as amended, Annex I(A) instruction [3]
How this site does it
The prescribed wording, with the address of the function in it, appears in the pre-contractual panel immediately above the order button, in the terms, in the withdrawal policy, and in the order confirmation document itself.
Right of withdrawalTerms, clause 6
src/pages/checkout.astrosrc/content/legal/withdrawal.mdsrc/lib/durable.ts -
Conditions, time limit and procedure — and the model form
ImplementedWhat the law requires
The trader must state the conditions, time limit and procedure for exercising the right of withdrawal, and make the Annex I(B) model withdrawal form available.
Art. 6(1)(h) and Annex I(B)
How this site does it
A dedicated withdrawal policy covering all three, plus the model form reproduced in full on its own page and offered as a download. The exceptions in Art. 16 are listed honestly, including the two that actually apply to clothing and the many that do not.
Right of withdrawalModel withdrawal form
src/content/legal/withdrawal.mdsrc/content/legal/model-form.md
Price reductions and the 30-day rule
Directive 98/6/EC as amended by Directive (EU) 2019/2161 (Omnibus)
Any announcement of a price reduction must state the prior price — defined as the lowest price the trader applied during at least the 30 days before the reduction. It is the most-broken rule in European e-commerce and the easiest to get right.
-
Every reduction states the lowest price of the previous 30 days
ImplementedWhat the law requires
Any announcement of a price reduction shall indicate the prior price, being the lowest price applied by the trader during a period of time not shorter than 30 days prior to the application of the price reduction.
Art. 6a(1) and 6a(2) of Directive 98/6/EC
How this site does it
Every product carries a real price history in its Markdown file, and one function derives the figure from it. The window ends when the current reduction began, not today, so a second cut cannot launder the first out of the comparison — and where an earlier promotion sits inside the window, the promotional price is the prior price, not the higher launch price. Unit-tested, including that case.
src/lib/pricing.tstests/pricing.test.mjs -
Stated as an exact amount, on the listing as well as the page
ImplementedWhat the law requires
The prior price must be indicated — as a figure. Vague claims such as “up to −50%” or “was 10% higher” do not discharge the obligation, and the announcement is made wherever the reduction is shown, including a listing card.
Art. 6a, read with Directive 2005/29/EC on misleading practices
How this site does it
One Price component renders the crossed-out figure, the percentage and an explicit “Lowest price in the 30 days before this reduction: €X” line — at body size, in full contrast, never in grey small print. It is the same component on the card, the product page and the basket, so the three cannot disagree.
src/components/Price.astrosrc/styles/global.css -
An RRP is never dressed up as a prior price
ImplementedWhat the law requires
A recommended retail price the trader never charged is not a prior price. Presenting it as the “was” figure overstates the saving and is a misleading action.
Art. 6a read with Art. 6 of Directive 2005/29/EC
How this site does it
The RRP is a separate field, rendered on its own line, labelled “Manufacturer’s recommended retail price”, and never used in the percentage calculation. The pricing function refuses to take it as an input for the prior price at all.
src/lib/pricing.tssrc/components/Price.astro -
A promotions page contains only promotions
ImplementedWhat the law requires
Advertising a sale and filling the page with full-price stock is a misleading commercial practice, as is a banner leading to products with no discount.
Arts. 6 and 7 of Directive 2005/29/EC
How this site does it
The sale page is generated from the products whose derived price view is actually on sale — it cannot contain anything else. The homepage promo states the real count and the real range of percentages, both computed from the same data.
src/lib/catalog.tssrc/pages/sale.astrosrc/pages/index.astro -
Reviews are from verified purchasers, and the bad ones stay up
ImplementedWhat the law requires
A trader stating that reviews are from consumers who bought the product must take reasonable and proportionate steps to verify it. Submitting or commissioning fake reviews, and suppressing negative ones, are both banned outright.
Art. 7(6) and Annex I points 23b–23c of Directive 2005/29/EC
How this site does it
Every review is marked verified against an order, the full 1-to-5 distribution is shown rather than an average alone, and every product carries at least one review below three stars with a specific public reply from us underneath it.
src/components/Reviews.astroscripts/lib/reviews.mjs
Pre-contractual information and the order process
Directive 2011/83/EU as amended by Directive (EU) 2019/2161
What must be told to the consumer before they are bound, and how the ordering control itself must be labelled.
-
The total price, inclusive of taxes, from the first figure
ImplementedWhat the law requires
The total price of the goods inclusive of taxes, and all additional freight, delivery or postal charges, must be given before the consumer is bound.
Art. 6(1)(e)
How this site does it
Every price on the site is gross. Delivery cost is stated on the product page next to the add-to-basket button, in the basket, and at every checkout step — and the checkout says in as many words that no fee is added later. There is no surcharge of any kind anywhere.
src/lib/shop.tssrc/lib/totals.tssrc/pages/p/[slug].astro -
The order button says it creates an obligation to pay
ImplementedWhat the law requires
Where placing the order entails an obligation to pay, the trader must make the consumer acknowledge that explicitly, and the ordering control must be labelled unambiguously with “order with obligation to pay” or a corresponding formulation. If not, the consumer is not bound.
Art. 8(2), second subparagraph
How this site does it
The final control reads “Order with obligation to pay — €X”, with the actual total in it. Nothing else on the checkout submits.
src/pages/checkout.astro -
Confirmation of the contract on a durable medium
ImplementedWhat the law requires
The trader must provide the consumer with confirmation of the concluded contract on a durable medium, within a reasonable time and at the latest at delivery.
Art. 8(7)
How this site does it
A complete confirmation document — parties, items, prices, VAT, delivery, payment method, the withdrawal information and the timestamp — downloadable as a self-contained file from the order page, and printable. Available for as long as the order exists.
src/lib/durable.tssrc/pages/order/index.astro -
Identity, geographical address and contact details
ImplementedWhat the law requires
The trader’s identity, geographical address, telephone number and e-mail address must be given, along with a means of communication allowing the consumer to keep a durable record.
Art. 6(1)(b)–(d) as amended
How this site does it
In the footer of every page and in full on the imprint, with the company registration, the VAT number and the supervisory authorities. The telephone number is a standard national number at the caller’s normal rate — Art. 21 forbids a premium line for contract matters.
src/lib/shop.tssrc/content/legal/imprint.md -
No account is required to buy, track or withdraw
ImplementedWhat the law requires
Not a requirement in itself — but an account wall in front of the withdrawal function breaches Art. 11a(1), and one in front of the order breaches nothing while costing the trader the sale.
Art. 11a(1); good practice elsewhere
How this site does it
There is no account system on this site. Checkout is a guest checkout because there is no alternative; orders are found by number and e-mail; the withdrawal function is public.
src/pages/checkout.astrosrc/pages/orders.astro
Conformity, delivery and redress
Directives (EU) 2019/771, 2011/83/EU and 2013/11/EU
What is owed after the sale, and what happens when something goes wrong.
-
Two-year legal guarantee of conformity
ImplementedWhat the law requires
The seller is liable for any lack of conformity existing at delivery and becoming apparent within two years. For the first year, the lack of conformity is presumed to have existed at delivery.
Arts. 10 and 11 of Directive (EU) 2019/771
How this site does it
Stated on every product page, in the terms with the remedies in their statutory order, and in the returns guide — separately from the right of withdrawal, because conflating the two is how a shop talks a customer out of a two-year right using a 30-day policy.
src/content/legal/terms.mdsrc/content/guides/returns.md -
Delivery within 30 days, and what happens if not
ImplementedWhat the law requires
The trader must deliver without undue delay and within 30 days. On failure the consumer may set an additional period and, if that passes, terminate the contract and be reimbursed.
Art. 18 of Directive 2011/83/EU
How this site does it
Delivery windows are computed in business days, skipping weekends and Irish public holidays, and shown as real dates on the product page and at checkout. The remedy is stated in the terms and in the delivery guide.
src/lib/dates.tssrc/content/guides/delivery.md -
Return postage, and who pays it
ImplementedWhat the law requires
The consumer bears the direct cost of returning the goods only if the trader informed them of that. If the trader failed to inform them, the trader bears it.
Arts. 6(1)(i) and 14(1)
How this site does it
We pay it, everywhere, and say so on the product page, in the basket, at checkout, in the acknowledgement and in the returns guide. The Directive permits charging the consumer; this is a deliberate choice not to.
src/content/guides/returns.md -
Complaints handling and alternative dispute resolution
ImplementedWhat the law requires
A trader committed to using an ADR entity must inform consumers of that entity and its website. The EU ODR platform ceased operating on 20 July 2025 and the duty to link to it was repealed with it.
Art. 13 of Directive 2013/11/EU; Regulation (EU) 2024/3228
How this site does it
A dedicated page naming the competent body, the ECC-Net route for cross-border buyers, response times we commit to, and the jurisdiction rules under Regulation (EU) 1215/2012 — including that we may sue a consumer only in their own country.
src/content/legal/dispute-resolution.md
Consent, cookies and personal data
Regulation (EU) 2016/679 (GDPR) and Directive 2002/58/EC (ePrivacy)
Storing anything on a visitor’s device needs consent unless it is strictly necessary — and the consent has to be a real choice, freely given and as easy to withdraw as to give.
-
Accept and reject are equally easy
ImplementedWhat the law requires
Consent must be freely given, specific, informed and unambiguous. The EDPB’s deceptive design guidance is explicit that a prominent “Accept” beside a buried or greyed-out “Reject” does not produce valid consent.
Arts. 4(11) and 7 GDPR; EDPB Guidelines 03/2022
How this site does it
Two buttons, same size, same row, one click each, neither styled as the obvious one. A third control opens per-purpose switches. Dismissing without choosing is not consent.
src/components/ConsentBanner.astro -
Withdrawing consent is as easy as giving it
ImplementedWhat the law requires
The data subject has the right to withdraw consent at any time, and it must be as easy to withdraw as to give.
Art. 7(3) GDPR
How this site does it
“Cookie settings” in the footer of every page reopens the same dialog with the current choice loaded. One click to get there, one to change it.
src/components/ConsentBanner.astrosrc/components/Footer.astro -
Nothing non-essential is stored before the choice
ImplementedWhat the law requires
Storing or accessing information on a user’s terminal equipment requires consent unless it is strictly necessary for a service the user explicitly requested. That covers localStorage, not only cookies.
Art. 5(3) of Directive 2002/58/EC
How this site does it
The site sets no cookies at all. localStorage holds only the basket, the checkout draft, orders, saved items and the consent record — each strictly necessary and each documented by key in the cookie notice. Analytics and marketing load nothing while off.
src/lib/store.tssrc/content/legal/cookies.md -
Erasure, immediately and completely
ImplementedWhat the law requires
The data subject has the right to obtain erasure of personal data concerning them without undue delay.
Art. 17 GDPR
How this site does it
One button that clears every key this site owns. Because there is no server, erasure is complete rather than a request someone has to honour — there is no second copy anywhere.
src/lib/store.tssrc/pages/legal/[slug].astro -
Portability without asking
ImplementedWhat the law requires
The data subject has the right to receive their data in a structured, commonly used and machine-readable format.
Art. 20 GDPR
How this site does it
Order confirmations and withdrawal acknowledgements download as self-contained HTML from the order page, on demand, with no request to make and nobody to make it to.
src/lib/durable.ts
Accessibility and interface quality
Directive (EU) 2019/882 (European Accessibility Act)
Applicable to e-commerce from 28 June 2025. Perceivable, operable, understandable and robust — in practice, WCAG 2.1 AA.
-
Every control is reachable with a thumb
ImplementedWhat the law requires
Target size and pointer cancellation are AA-level success criteria; a control that cannot be hit reliably is not operable.
EN 301 549 / WCAG 2.1 AA (2.5.5, 2.5.2)
How this site does it
A 44×44 CSS-pixel minimum on every interactive element, enforced by a design token rather than remembered case by case. Filter-removal buttons are 28px inside a 44px row; consent checkboxes are 24px inside a 44px label.
src/styles/global.css -
Labels, errors and autofill
ImplementedWhat the law requires
Form inputs need visible labels, errors must identify the field and describe the fix, and the purpose of each input must be programmatically determinable so a browser can fill it.
WCAG 2.1 AA (1.3.5, 3.3.1, 3.3.2, 3.3.3)
How this site does it
Every field has a visible label above it, not a placeholder that vanishes. Required fields are marked for sighted and for screen-reader users. Errors appear under the field and in a summary at the top, each one saying how to fix it, and validation runs on blur rather than mid-word. Every field carries the right autocomplete token and inputmode.
src/pages/checkout.astrosrc/styles/global.css -
Nothing moves after it has been drawn
ImplementedWhat the law requires
Not a legal requirement — a usability one. A tap that lands on the wrong control because the page moved is a failed interaction.
Good practice; supports WCAG 3.2.5
How this site does it
No web fonts, no external requests, no client-side rendered product grids. Every image is inline SVG in a box with a fixed aspect ratio, so it occupies its space before it draws. The consent banner and the sticky buy bar are fixed-position and reserve their own room.
src/components/ProductImage.astrosrc/layouts/Base.astro -
Light, dark and reduced motion are all honoured
ImplementedWhat the law requires
Content must be usable in the user’s chosen presentation, and motion must be avoidable.
WCAG 2.1 AA (1.4.3, 2.3.3)
How this site does it
A full token palette for both schemes with contrast checked in each, and every transition reduced to nothing under prefers-reduced-motion.
Try switching your system theme
src/styles/global.css
What this deliberately does not do
A reference implementation is only useful if it is honest about its edges, so here are this one's:
- No e-mail. There is no server, so nothing is ever sent. The order confirmation and the withdrawal acknowledgement are handed over directly instead — on screen and as files you download and keep, which is a durable medium in its own right. A live deployment would send the same documents by e-mail as well.
- No payment. No money moves, no card field exists, and no order is ever dispatched. The payment step models the choice a real checkout offers, including methods that charge nothing at the moment of ordering.
- State is per-browser. Orders live in the browser that placed them, so an order number from another device cannot be looked up. A withdrawal declared against an unknown order number is still recorded and still acknowledged with its timestamp — the right of withdrawal does not become conditional on a lookup succeeding.
- One country, one language. Ireland, English, EUR, 23% VAT. A shop selling into several member states owes each storefront its own compliant interface, its own language, and its own withdrawal function — and one perfect English form says nothing about the German one.
- Product imagery is drawn, not photographed. The catalogue is generated, so every garment is rendered as SVG from its shape and colourway. Real photography — worn, flat, close-up and against a scale — is what a real shop owes its customers.
Found something wrong? That is the most useful thing you could tell us: support@ideal-commerce.example.