Installation
Install the package
npm install srcdev-hair-treatmentsImport the styles
Two stylesheets ship in dist/: the component's own CSS, and a set of colour tokens it reads from. Import both once, globally, in your app's entry point or global CSS:
@import "srcdev-hair-treatments/dist/style.css";
@import "srcdev-hair-treatments/dist/tokens.css";tokens.css defines the four semantic colour ramps the component uses: --brand-00 through --brand-10, plus --success-*, --warning-* and --error-*. Skip this import and provide your own values instead if you want the widget themed to match your brand from the start — see Theming.
Copy the images
Hair type and colour swatches can show real photography — the package ships a full set of default images, but they need to be served from your own app's public/ directory, not read from node_modules. Add a script to your package.json and run it once after install:
"setup:assets": "cp -r node_modules/srcdev-hair-treatments/public/images/. public/images/"Wire it into a postinstall hook so it stays in sync on every npm install, picking up any new or changed images on a package update:
"postinstall": "npm run setup:assets"See Theming → Images for overriding these with your own photography per option.
Register the plugin
createHairTreatments() is a Vue plugin that provides a default config to every TreatmentConsultant instance in your app. Passing a config here is optional — you can also pass one directly as a prop per-instance (see Configuration). It can also carry your license key so you don't have to repeat it per instance — see Licensing.
import { createApp } from "vue"
import { createHairTreatments } from "srcdev-hair-treatments"
import App from "./App.vue"
const app = createApp(App)
app.use(createHairTreatments())
app.mount("#app")Use the component
<template>
<TreatmentConsultant @complete="onComplete" />
</template>
<script setup lang="ts">
import { TreatmentConsultant } from "srcdev-hair-treatments"
import type { ConsultationSelections } from "srcdev-hair-treatments"
function onComplete(selections: ConsultationSelections) {
console.log(selections)
}
<\/script>Nuxt
Register the plugin under app/plugins/ (not a root-level plugins/ directory — Nuxt 4's default srcDir is app/, and a plugin outside it silently won't register):
// app/plugins/hair-treatments.ts
import { createHairTreatments } from "srcdev-hair-treatments"
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(createHairTreatments())
})Add both stylesheets to nuxt.config.ts's css array, and wrap the component itself in <ClientOnly> — TreatmentConsultant is not SSR-safe. Full details in SSR & ClientOnly.
Plain HTML — no build step
No Vue app, no bundler? A separate dist/embed.js bundle ships everything needed — Vue included — so a plain HTML page can embed the consultation with a <div>, a stylesheet link, and one <script> tag. Loaded from a CDN like jsDelivr, the URL is pinned to a package version, so there's nothing to cache-bust when a new version ships — just bump the version in the URL when you want it.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/srcdev-hair-treatments@1.1.3/dist/embed-style.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/srcdev-hair-treatments@1.1.3/dist/tokens.css" />
<div data-hair-treatments data-license-key="YOUR_LICENSE_KEY"></div>
<script
type="module"
src="https://cdn.jsdelivr.net/npm/srcdev-hair-treatments@1.1.3/dist/embed.js"
></script>Every element on the page matching [data-hair-treatments] is mounted automatically once the script loads — nothing else to write. The version above, 1.1.3, is read from this site's own installed dependency, so it's always current — copy it as-is, or replace it with whichever version you've pinned to yourself. See Licensing for where the license key comes from.
Pass configuration per-instance with a JSON-encoded data-config attribute — see Configuration for the shape it accepts:
<div
data-hair-treatments
data-license-key="YOUR_LICENSE_KEY"
data-config="{"text": {"heading": "Find your perfect colour"}}"
></div>There's no Vue app here for @complete/@change to hook into, so the embed bundle re-dispatches them as native CustomEvents on the mount element instead — listen with addEventListener:
document
.querySelector("[data-hair-treatments]")
.addEventListener("hair-treatments:complete", (event) => {
console.log(event.detail) // ConsultationSelections
})