Ivora — Dental Clinic Template

Dental & medical clinic website with online booking and a patient portal. Static HTML, CSS and JavaScript.

Quick start

  1. Unzip the package.
  2. Open template/index.html in your browser. Everything works straight from disk, with no build step and no server.
  3. Edit template/assets/js/data.js to set your clinic name, treatments, prices, dentists and opening hours.
  4. Replace the photos in template/assets/img/ with your own (keep the same file names, or update the paths).
  5. 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-endpoint attribute 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 file

Customise & 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 dentists array lists who performs it. The booking flow only offers those dentists.
  • A dentist's off array lists weekdays they do not work (0 = Sunday).
  • img is the file name in assets/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:

FunctionReplace 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 as FormData with Accept: 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.

Licence and production activation

Single-domain and Full-source purchases each activate one production hostname. Full source adds editable code, white-label and SaaS rights; it does not include unlimited installations or redistribution. Localhost and .test development hosts are allowed.

Set the delivered key and production hostname in LICENSING/licence.json. Use https://vortaxis.com/licence/ to view activation or request a domain transfer. Vortaxis Studio approves replacement domains. Production activation requires a network connection; public demos remain unrestricted.

See LICENSE.txt for the complete terms. Existing purchases retain their original terms.