Ivora — Dental Clinic Template
Dental & medical clinic website with online booking and a patient portal. Static HTML, CSS and JavaScript.
Quick start
- Unzip the package.
- Open
template/index.htmlin your browser. Everything works straight from disk, with no build step and no server. - Edit
template/assets/js/data.jsto set your clinic name, treatments, prices, dentists and opening hours. - Replace the photos in
template/assets/img/with your own (keep the same file names, or update the paths). - Upload the contents of
template/to any static host (shared hosting, Netlify, Vercel, GitHub Pages, S3…).
Features
- 7 pages + 404: home, treatments, treatment detail, dentists, online booking, contact and a patient portal.
- Online booking flow: treatment → dentist (or “any available”) → date & time → details → confirmation. It shows live free and booked slots based on opening hours, each dentist's days off and treatment length, and has deep links (
booking.html?t=teeth-whitening&d=amelia-hart), an “Add to calendar” (.ics) download and reschedule support. - Patient portal (front-end mock): sign-in, overview dashboard, appointments with cancel and reschedule, treatment plan with progress, invoices, documents, messages and profile.
- Data-driven: one file (
data.js) feeds treatment cards, dentist cards, offers, reviews, FAQ, the treatment detail page and the booking calendar. - Treatment detail page: one template page (
treatment.html?t=slug) for every treatment, with steps, inclusions, price box, FAQ, dentists and related treatments. - Dentist profiles: filter by specialty, accessible profile dialog and one-click “Book with”.
- Contact form with validation, honeypot and a
data-endpointattribute for any form service. - Design: calm premium look with self-hosted fonts (Fraunces + Figtree), 20+ inline SVG icons, scroll reveal animations (respecting “reduce motion”) and a sticky header with a mobile drawer.
- Responsive from 360px phones to wide desktops, with a floating “Book” button on phones.
- Accessible basics: skip link, landmarks, labelled form fields, visible focus, ARIA on steps, radios and dialogs, Escape closes dialogs.
- No dependencies: no frameworks, no CDNs, no external requests, no build step.
File structure
template/
index.html Home: hero, treatments, why us, dentists, offers, reviews, FAQ
treatments.html All treatments with category filter
treatment.html Treatment detail (treatment.html?t=<slug>)
dentists.html Team with specialty filter + profile dialog
booking.html 5-step online booking
contact.html Contact form, hours, map
portal.html Patient portal (sign-in + dashboard)
404.html Not-found page
assets/
css/style.css All styles (design tokens at the top)
js/data.js ← your clinic data: treatments, dentists, offers, reviews, FAQ, hours
js/icons.js Inline SVG icon set
js/render.js Card renderers used by all lists
js/main.js Header, menu, filters, dialog, forms, animations
js/treatment.js Treatment detail page
js/store.js Appointment storage + slot calculation (replace for a real backend)
js/booking.js Booking flow
js/portal.js Patient portal
fonts/ Fraunces + Figtree (woff2) with licences
img/ Sample photos, favicon, social image
documentation/ This fileCustomise & rebrand
Clinic data
Open assets/js/data.js. CLINIC holds the name, currency symbol, phone, email, address, opening hours (used by the booking calendar), slot length and how many days ahead patients can book. TREATMENTS, DENTISTS, OFFERS, REVIEWS and FAQ are plain arrays. Add, remove or reorder items and every page updates.
- A treatment's
dentistsarray lists who performs it. The booking flow only offers those dentists. - A dentist's
offarray lists weekdays they do not work (0 = Sunday). imgis the file name inassets/img/without the size suffix and extension.
How the lists work: elements with data-list="treatments" (and similar) are filled from data.js when the page loads. The HTML already inside them is a pre-rendered copy for search engines and visitors without JavaScript. After you change data.js, you can paste the new markup in, or leave the old copy: visitors always see the current data.
Colours & fonts
All colours are CSS variables at the top of assets/css/style.css (--navy, --teal, --gold, --mint, --sand…). Change them to restyle the whole site. To use other fonts, replace the woff2 files and the @font-face rules, then update --serif and --sans.
Logo
The logo is an inline SVG inside .logo in the header, menu and footer of each page, plus assets/img/favicon.svg. Replace the SVG or swap it for an <img>.
Texts in the header and footer
The top bar (hours, phone, email), footer and page texts are plain HTML in each page. Search and replace “Ivora”, the phone number and the address across the files.
Photos
Replace the files in assets/img/. Landscape photos come in two widths (-800/-1400, clinic -900/-1600) and portraits at 720×960. Any size works if you keep the aspect ratio roughly the same.
Map
The contact page shows an illustrated map so the template makes no external requests. Replace the .map block with your map provider's embed code (an <iframe>) when you go live.
Booking & portal: demo mode and going live
Out of the box, bookings are saved in the visitor's browser (localStorage), so the full flow and the patient portal work on any static host with no server. That is ideal for demos, presentations and client approval.
For a live clinic, connect the flow to a real booking system (your practice-management software API, a booking SaaS, or your own backend). All storage and availability logic is in assets/js/store.js:
| Function | Replace with |
|---|---|
Store.slots(date, dentist, treatment) | GET free times for a day from your API |
Store.days(dentist, treatment) | GET days with availability (or compute from slots) |
Store.add(booking) | POST the booking. In booking.js → confirmBooking(), wait for the response before showing the confirmation. |
Store.all() / Store.upcoming() | GET the signed-in patient's appointments |
Store.cancel(ref) | DELETE / cancel the appointment |
The portal's sign-in is a mock (any email and password). Real patient accounts need a backend with authentication. Treat the portal as the front-end design to connect to it. Invoices, documents and the treatment plan in portal.js are sample data.
Clear the demo data any time with localStorage.clear() in the browser console. All keys start with ivora. (set by CLINIC.storageKey).
Contact form
The contact form has a data-endpoint attribute:
data-endpoint=""(default) is demo mode: fields are validated and the success message is shown, but nothing is sent.data-endpoint="https://formspree.io/f/xxxx", or your own script URL: the fields are POSTed asFormDatawithAccept: application/json. Any 2xx response shows the success message. Errors show the error message.
<form data-endpoint="https://your-form-service.example/endpoint" novalidate>
Fields with required are checked, and email and phone formats are validated. The hidden website field is a spam honeypot.
Browser support
Current versions of Chrome, Edge, Firefox and Safari (desktop and mobile). Uses CSS grid, custom properties, backdrop-filter (with a solid fallback), IntersectionObserver (content shows even without it) and localStorage.
FAQ
Can I use it for a medical (non-dental) clinic?
Yes. Change the treatments, icons and texts in data.js. The booking flow works for any appointment-based practice: physio, dermatology, aesthetics, vets and more.
Does it take payments or store patient data on a server?
No. It is a static front-end. Bookings stay in the browser until you connect a backend (see “Booking & portal”).
Can I add a treatment?
Add an object to TREATMENTS in data.js. It appears in the lists, gets its own detail page at treatment.html?t=your-slug and is bookable at once.
Which licence do I need?
The Licence covers one end product (your clinic's site or one client's). Full source covers one production domain for you and your clients, including white-label and SaaS use. Neither allows reselling the template itself.
Support
Questions or found a bug? Email hello@vortaxis.com with your order reference. Item questions are answered for 6 months after purchase (12 months with Full source). Updates are free.