@consenta/vue
@consenta/vue
Vue 3 binding cho Consenta Data Consent SDK — Vue thuần dựng trên headless core
(@consenta/core). Không bọc web component: mọi nghiệp vụ (tải config, state, validate, build
payload, submit) nằm ở core; package này chỉ nối vòng đời Vue (an toàn SSR/Nuxt).
Cài đặt
npm install @consenta/vue @consenta/core
vuelà peerDependency (^3.3.0) — dùng bản Vue sẵn có của ứng dụng.
Dùng nhanh — <ConsentForm/>
<script setup lang="ts">
import { ConsentForm } from '@consenta/vue';
import type { ConsentPayload } from '@consenta/vue';
function onSubmit(payload: ConsentPayload) {
console.log('consentId:', payload.consentId);
}
</script>
<template>
<ConsentForm
code-config="cp_...::t_..."
language="vi"
show-reject
@submit="onSubmit"
@error="(e) => console.error(e)"
/>
</template>
Style mặc định được chèn 1 lần vào <head> (idempotent, an toàn SSR). Tắt bằng unstyled
và tự style qua class-names.
Sau khi gửi thành công, component thay form bằng panel xác nhận; khi lỗi, hiện banner kèm
message do server trả. Muốn tự hiển thị thông báo → dùng no-success-ui.
Giao diện
Cùng bố cục với <cst-consent-form> của @consenta/web:
- Header: tiêu đề + "Hiện danh sách / Ẩn danh sách", "Chi tiết / Thu gọn" (mở/đóng trường dữ liệu của mọi mục đích — chỉ hiện khi danh sách đang mở) và công tắc "Đồng ý tất cả" (bật/tắt mọi mục đích đang hiển thị, giữ nguyên mục đích bắt buộc; bị khoá khi mọi mục đích đều bắt buộc).
- Dưới tiêu đề là mô tả của mẫu consent (
config.description). - Danh sách mục đích mặc định ẩn; bật
default-list-expandedđể hiện sẵn. Mỗi mục đích: tên (+*nếu bắt buộc) kèm nút "Chi tiết" ngay cạnh, switch bên phải, mô tả bên dưới (dài hơn 120 ký tự thì thu gọn 2 dòng + "Xem thêm"). - "Chi tiết" mở các trường dữ liệu: mỗi trường một switch nhỏ (chỉ đổi được khi mục đích đang bật) +
tag bên thứ ba. Trường CMP trả
display: falsekhông hiển thị và không tính là bắt buộc, nhưng vẫn được gửi theo trạng thái của mục đích. - Collection point tạm ngừng (Config API trả 410): component không render gì,
status='suspended', sự kiện@suspendedđược gọi,isValid=truevàsubmit()trả{ ok: false, error: 'suspended' }(CONSENT_SUSPENDED_ERROR) — host nên cho luồng của mình đi tiếp.
Gộp consent vào form của bạn (manual-submit + template ref)
Khi muốn 1 nút duy nhất gửi cả form của bạn lẫn consent: ẩn nút của SDK bằng manual-submit,
rồi gọi submitConsent() qua template ref.
<script setup lang="ts">
import { reactive, useTemplateRef } from 'vue';
import { CONSENT_SUSPENDED_ERROR, ConsentForm } from '@consenta/vue';
import type { ConsentFormHandle } from '@consenta/vue';
const consent = useTemplateRef<ConsentFormHandle>('consent');
const form = reactive({ name: '', email: '' });
async function handleSubmit() {
// Giá trị field: key theo field id CMP HOẶC nhãn field ("Họ và tên")
const result = await consent.value?.submitConsent({
'Họ và tên': form.name,
Email: form.email,
});
// 'suspended' = tenant đã tạm ngừng collection point → không cần consent, gửi form như thường.
if (!result?.ok && result?.error !== CONSENT_SUSPENDED_ERROR) return; // lỗi → không gửi form
await saveContact(form); // consent OK → gửi form của bạn
}
</script>
<template>
<form @submit.prevent="handleSubmit">
<input v-model="form.name" />
<input v-model="form.email" type="email" />
<ConsentForm
ref="consent"
code-config="cp_...::t_..."
variant="embedded"
manual-submit
no-success-ui
/>
<button type="submit">Gửi</button>
</form>
</template>
ref cung cấp: submitConsent(fieldValues?) → { ok, consentId?, error? }, isValid(), getState(),
isSuspended(). error có thể là message server, CONSENT_NOT_READY_ERROR ('not-ready' — chưa tải
xong config) hoặc CONSENT_SUSPENDED_ERROR ('suspended' — collection point tạm ngừng).
Vue < 3.5 chưa có
useTemplateRef→ dùngconst consent = ref<ConsentFormHandle | null>(null)với<ConsentForm ref="consent" …/>(Options API:this.$refs.consent).
Giá trị field (fieldValues)
- Key theo field id CMP hoặc nhãn field (SDK khớp id → name → nhãn chuẩn hoá
ho_va_ten). valuechỉ đính khi người dùng đã đồng ý field đó — không gửi dữ liệu cho mục đích/field bị tắt.- Có thể khai sẵn qua prop
field-values; giá trị truyền vàosubmitConsent()/submit()sẽ đè lên.
Visitor ID (cmp_vid)
Mỗi lần gửi, SDK đọc trước khoá cmp_vid trong localStorage; chưa có thì sinh UUID mới và
lưu lại, rồi gửi kèm payload dưới trường visitorId. Nhờ đó CMP nối được Data Consent với Cookie
Consent của cùng một trình duyệt — khoá và định dạng dùng chung với SDK cookie banner, bên nào
chạy trước cũng được. Mặc định bật, không cần cấu hình.
<ConsentForm code-config="…" visitor-id="7f75efa3-…" />
<!-- dùng cmp_vid có sẵn (phải là UUID) -->
<ConsentForm code-config="…" :visitor-id="null" />
<!-- TẮT: không đọc, không tạo, không gửi -->
visitor-id phải là UUID (định dạng cmp_vid dùng chung với SDK cookie banner). Giá trị sai định
dạng bị bỏ qua (có cảnh báo trên console) và SDK tự đọc/sinh cmp_vid như khi bỏ trống.
Headless — useConsent()
Tự dựng UI riêng, vẫn tái dùng toàn bộ logic core:
<script setup lang="ts">
import { useConsent } from '@consenta/vue';
// Destructure được vì composable trả object chứa các ref → template tự unwrap.
const { status, config, state, engine, error, errorMessage, submitting, setPurpose, submit } =
useConsent({ codeConfig: 'cp_...::t_...' });
</script>
<template>
<p v-if="status !== 'ready'">Đang tải…</p>
<template v-else>
<label v-for="p in config?.items" :key="p.id">
<input
type="checkbox"
:checked="state?.purposes[p.id]?.accepted ?? false"
:disabled="engine?.isPurposeRequired(p.id)"
@change="setPurpose(p.id, ($event.target as HTMLInputElement).checked)"
/>
{{ p.label }}
</label>
<button :disabled="submitting" @click="submit()">Đồng ý</button>
<p v-if="error != null" role="alert">{{ errorMessage ?? 'Gửi consent thất bại.' }}</p>
</template>
</template>
submit(fieldValues?) không ném lỗi — trả { ok, consentId?, error? }; composable cũng expose
errorMessage (ưu tiên message server), submitting, submitted, isValid, reload.
status là 'loading' | 'ready' | 'error' | 'suspended'. Engine core có sẵn
engine.getVisiblePurposes(), engine.getVisibleFields(id), engine.isAllAccepted(),
engine.hasOptionalPurpose() để dựng header "Đồng ý tất cả" và bỏ mục/trường display: false.
Mọi option nhận giá trị, ref hoặc getter (MaybeRefOrGetter): đổi codeConfig/baseUrl sẽ
tự tải lại config.
Nuxt 3 / SSR
Không cần <ClientOnly>: khi SSR, component render trạng thái "đang tải" và không gọi API
(request chỉ chạy trong onMounted), nên không có hydration mismatch.
<!-- pages/dang-ky.vue -->
<script setup lang="ts">
import { ConsentForm } from '@consenta/vue';
</script>
<template>
<ConsentForm code-config="cp_...::t_..." />
</template>
Props chính của <ConsentForm/>
| Prop (template) | Kiểu | Mặc định | Ý nghĩa |
|---|---|---|---|
code-config |
string |
— | Integration key (bắt buộc) |
base-url |
string |
prod CMP | Override CMP (vd dev localhost:8082) |
language |
'vi' | 'en' |
'vi' |
Ngôn ngữ nhãn UI |
variant |
'card' | 'embedded' |
'card' |
embedded = khung phẳng để nhúng trong form |
show-reject |
boolean |
false |
Hiện nút "Từ chối tất cả" |
default-list-expanded |
boolean |
false |
Hiện sẵn danh sách mục đích |
default-expanded |
boolean |
false |
Mở sẵn phần trường dữ liệu |
manual-submit |
boolean |
false |
Ẩn thanh nút; host gửi qua ref |
no-success-ui |
boolean |
false |
Không thay form bằng panel thành công |
field-values |
object |
— | Giá trị field đính vào payload |
visitor-id |
string | null |
tự đọc | Ghi đè cmp_vid (UUID); null = tắt hẳn |
unstyled / class-names |
— | — | Tùy biến style |
Sự kiện: @ready (config), @change (state), @submit (payload), @error (error),
@suspended (collection point tạm ngừng).
Ngoài ra <ConsentForm/> expose template ref (ConsentFormHandle): submitConsent(fieldValues?),
isValid(), getState(), isSuspended().
Theming
Giá trị mặc định của biến --cst-* được khai trong :where(.cst-consent) (độ ưu tiên 0), nên
selector bất kỳ của bạn nhắm vào .cst-consent đều ghi đè được:
.my-form .cst-consent {
--cst-accent: #0f766e;
--cst-radius: 10px;
}
Biến có sẵn: --cst-accent, --cst-text, --cst-muted, --cst-required, --cst-border,
--cst-surface, --cst-subtle, --cst-radius, --cst-radius-sm, --cst-gap, --cst-font,
--cst-padding, --cst-shadow, --cst-container-border.
Xem thêm useConsent để build payload/submit thủ công.
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.2.0 | ^3.3.0 | MIT | |
| 0.1.0 | ^3.3.0 | MIT |