javascript / intermediate
Snippet
Sanitizing Rich HTML Directives Against XSS with DOMPurify
Using Vue's native v-html directive exposes components to Cross-Site Scripting (XSS) if raw user input contains executable markup. By implementing a custom directive that sanitizes HTML input via DOMPurify before writing directly to innerHTML, applications enforce strict security constraints on permitted tags and attributes across component mount and update cycles.
snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { type Directive } from 'vue';import DOMPurify from 'dompurify';export const vSafeHtml: Directive<HTMLElement, string | null> = {mounted(el, binding) {const rawInput = binding.value;if (typeof rawInput !== 'string' || !rawInput.trim()) {el.textContent = '';return;}const sanitized = DOMPurify.sanitize(rawInput, {ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'code'],ALLOWED_ATTR: ['href', 'target', 'rel']});el.innerHTML = sanitized;},updated(el, binding) {if (binding.value !== binding.oldValue) {vSafeHtml.mounted?.(el, binding, null as any, null as any);}}};
vue
Breakdown
1
export const vSafeHtml: Directive<HTMLElement, string | null> = {
Defines a typed Vue custom directive accepting an HTML element target and a nullable string value binding.
2
if (typeof rawInput !== 'string' || !rawInput.trim()) {
Performs defensive control-flow type checks to clear content safely when inputs are non-strings or empty.
3
const sanitized = DOMPurify.sanitize(rawInput, {
Runs DOMPurify with an explicit tag and attribute whitelist to strip malicious scripts and handlers.
4
if (binding.value !== binding.oldValue) {
Checks whether the bound string value changed to prevent redundant DOM updates and sanitization passes.