safeHtml
Paquete: @tiendana/ngx-core/ui
Pipe que marca un HTML como confiable con DomSanitizer.bypassSecurityTrustHtml, para renderizarlo con [innerHTML] sin que Angular lo sanitice.
Características
✅ Bypass de seguridad para HTML confiable
✅ Manejo de null/undefined
✅ Integración con DomSanitizer
API
Transform
transform(html: string | null | undefined): unknown // SafeHtml, o '' si html es null/undefined
| Parámetro | Tipo | Retorno |
|---|---|---|
html | string | null | undefined | SafeHtml (HTML marcado como confiable) o string vacío |
Uso
<div [innerHTML]="htmlContent | safeHtml"></div>
Ejemplo Completo
import { Component, signal } from '@angular/core';
import { SafeHtmlPipe } from '@tiendana/ngx-core/ui';
@Component({
imports: [SafeHtmlPipe],
template: `
<div [innerHTML]="richText() | safeHtml"></div>
`
})
export class ArticleComponent {
richText = signal(`
<h1>Título</h1>
<p>Párrafo con <strong>negrita</strong> y <em>cursiva</em>.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
`);
}
Con Contenido Dinámico
@Component({
template: `
<textarea [value]="html()" (input)="html.set($any($event.target).value)">
</textarea>
<h3>Preview:</h3>
<div [innerHTML]="html() | safeHtml"></div>
`
})
export class HtmlEditorComponent {
html = signal('<p>Edita el HTML aquí</p>');
}
Implementación
import { inject, Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({ name: 'safeHtml' })
export class SafeHtmlPipe implements PipeTransform {
private sanitizer = inject(DomSanitizer);
transform(html: string | null | undefined): unknown {
if (html === null || html === undefined) {
return '';
}
return this.sanitizer.bypassSecurityTrustHtml(html);
}
}
Manejo de Null
// null o undefined retorna string vacío
<div [innerHTML]="null | safeHtml"></div>
<!-- Renderiza: <div></div> -->
<div [innerHTML]="undefined | safeHtml"></div>
<!-- Renderiza: <div></div> -->
Seguridad
⚠️ Importante: Solo usa este pipe con HTML confiable (de tu backend, editores controlados, etc.).
// ✅ Seguro - HTML de tu API
<div [innerHTML]="article.content | safeHtml"></div>
// ❌ Peligroso - Input de usuario sin sanitizar
<div [innerHTML]="userInput | safeHtml"></div>
XSS Protection
Angular sanitiza HTML por defecto. Este pipe bypasa esa protección:
// Sin pipe - Angular sanitiza automáticamente
<div [innerHTML]="html"></div>
<!-- Scripts no se ejecutan -->
// Con pipe - Bypass de sanitización
<div [innerHTML]="html | safeHtml"></div>
<!-- Scripts SÍ se ejecutan - ¡Cuidado! -->
Casos de Uso
CMS Content
@Component({
template: `
<article [innerHTML]="cmsContent() | safeHtml"></article>
`
})
export class CMSArticleComponent {
cmsContent = signal('');
async ngOnInit() {
const data = await this.api.getArticle(this.id);
this.cmsContent.set(data.html);
}
}
Email Templates
<div class="email-preview" [innerHTML]="emailTemplate | safeHtml"></div>
Rich Text Editor Output
<div [innerHTML]="editorOutput | safeHtml"></div>
Alternativas
Si el HTML viene de usuarios, considera:
- Sanitizar en backend antes de guardar
- Usar librerías como
DOMPurify - Markdown en lugar de HTML directo
Combinación con highlightedText
// highlightedText retorna un string con <span class="highlighted-text">;
// [innerHTML] lo sanitiza y conserva el span y su clase
<div [innerHTML]="text | highlightedText:searchTerm"></div>
// No necesitas safeHtml adicional, y bypasar la sanitización
// sobre texto que viene del usuario es inseguro
<div [innerHTML]="text | highlightedText:searchTerm | safeHtml"></div>
<!-- ❌ Innecesario -->
Performance
- Usa
pure: truepor defecto (cacheo automático) - Solo re-evalúa cuando cambia el input
- Lightweight - solo wrapper de DomSanitizer