npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

xss-safe-display

v0.1.0

Published

A TypeScript library for safe display and sanitization to prevent XSS attacks.

Downloads

37

Readme

XSS Safe Display

Features

  • 🛡️ XSS Protection - Comprehensive sanitization utilities
  • 📝 Safe Text Display - HTML escaping for user content
  • 🎨 Controlled HTML Rendering - Allowlist-based HTML sanitization
  • 🔗 URL Validation - Malicious URL scheme prevention
  • 🔧 Object Sanitization - Recursive object property cleaning
  • TypeScript Support - Full type safety and IntelliSense
  • ⚛️ React Integration - Ready-to-use with React components

Installation

npm install xss-safe-display
yarn add xss-safe-display
pnpm add xss-safe-display

Quick Start

import { safeDisplay, sanitizeHTML, escapeHTML } from 'xss-safe-display';

// Safe text display
const userInput = "<script>alert('xss')</script>";
const safeText = safeDisplay.text(userInput);
console.log(safeText); // "&lt;script&gt;alert('xss')&lt;/script&gt;"

// Safe HTML with allowed tags
const htmlContent = "<p>Hello</p><script>alert('bad')</script>";
const safeHtml = safeDisplay.html(htmlContent, ['p', 'strong']);
// Returns: { __html: "<p>Hello</p>" }

// URL sanitization
const safeUrl = safeDisplay.url("javascript:alert('xss')");
console.log(safeUrl); // Returns safe fallback or empty string

API Reference

Named Exports

import { 
  sanitizeString,
  sanitizeHTML,
  sanitizeObject,
  escapeHTML,
  sanitizeUrl,
  safeDisplay 
} from 'xss-safe-display';

Core Sanitization Functions

sanitizeString(input: string): string

Sanitizes string content to prevent XSS attacks.

sanitizeHTML(content: string, allowedTags?: string[]): string

Safely sanitizes HTML content with configurable allowed tags.

sanitizeObject(obj: any): any

Recursively sanitizes object properties.

escapeHTML(text: string): string

Escapes HTML special characters.

sanitizeUrl(url: string): string

Validates and sanitizes URLs to prevent malicious schemes.

safeDisplay Object

safeDisplay.text(value: string | number | undefined | null): string

Safely displays text content by escaping HTML characters.

const userInput = "<img src=x onerror=alert('xss')>";
const safe = safeDisplay.text(userInput);
// Returns: "&lt;img src=x onerror=alert('xss')&gt;"

// Handles all data types safely
safeDisplay.text(null);      // ""
safeDisplay.text(undefined); // ""
safeDisplay.text(123);       // "123"

safeDisplay.html(content: string, allowedTags?: string[]): { __html: string }

Sanitizes HTML and returns React-compatible object.

const blogPost = `
  <h1>My Post</h1>
  <p>Safe content</p>
  <script>alert('malicious')</script>
  <img src="x" onerror="alert('bad')">
`;

const safeHtml = safeDisplay.html(blogPost, ['h1', 'p', 'strong', 'em']);
// Only allowed tags are preserved, scripts are removed

safeDisplay.url(url: string): string

Validates and sanitizes URLs.

safeDisplay.url("https://example.com");           // "https://example.com"
safeDisplay.url("http://example.com");            // "http://example.com"
safeDisplay.url("/relative/path");                // "/relative/path"
safeDisplay.url("javascript:alert('xss')");       // "" (blocked)
safeDisplay.url("data:text/html,<script>...");    // "" (blocked)

Framework Integration

React

import React from 'react';
import { safeDisplay } from 'xss-safe-display';

// Safe text component
function SafeText({ children }: { children: any }) {
  return <span>{safeDisplay.text(children)}</span>;
}

// Safe HTML component
function SafeHTML({ content, allowedTags = ['p', 'strong', 'em'] }: {
  content: string;
  allowedTags?: string[];
}) {
  return (
    <div 
      dangerouslySetInnerHTML={safeDisplay.html(content, allowedTags)} 
    />
  );
}

// Safe link component
function SafeLink({ href, children }: { 
  href: string; 
  children: React.ReactNode; 
}) {
  const safeHref = safeDisplay.url(href);
  
  return (
    <a href={safeHref} rel="noopener noreferrer">
      {safeDisplay.text(children)}
    </a>
  );
}

Vue.js

<template>
  <div>
    <!-- Safe text binding -->
    <p>{{ safeText(userInput) }}</p>
    
    <!-- Safe HTML rendering -->
    <div v-html="safeHtml(content, ['p', 'strong'])"></div>
    
    <!-- Safe link -->
    <a :href="safeUrl(link)">{{ safeText(linkText) }}</a>
  </div>
</template>

<script setup>
import { safeDisplay } from 'xss-safe-display';

const safeText = safeDisplay.text;
const safeHtml = (content, tags) => safeDisplay.html(content, tags).__html;
const safeUrl = safeDisplay.url;
</script>

Angular

import { Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { safeDisplay } from 'xss-safe-display';

@Component({
  selector: 'app-safe-content',
  template: `
    <div [innerHTML]="safeHtmlContent"></div>
    <p>{{ safeTextContent }}</p>
    <a [href]="safeLinkUrl">Safe Link</a>
  `
})
export class SafeContentComponent {
  safeTextContent: string;
  safeHtmlContent: SafeHtml;
  safeLinkUrl: string;

  constructor(private sanitizer: DomSanitizer) {
    // Note: Angular's DomSanitizer provides additional security layer
    this.safeTextContent = safeDisplay.text(userInput);
    this.safeHtmlContent = this.sanitizer.bypassSecurityTrustHtml(
      safeDisplay.html(htmlContent, ['p', 'strong']).__html
    );
    this.safeLinkUrl = safeDisplay.url(userUrl);
  }
}

Common Use Cases

User-Generated Content

import { safeDisplay, sanitizeObject } from 'xss-safe-display';

// Blog comments
function displayComment(comment: { author: string; content: string; avatar?: string }) {
  const safeComment = sanitizeObject(comment);
  
  return {
    author: safeDisplay.text(safeComment.author),
    content: safeDisplay.html(safeComment.content, ['p', 'br', 'strong', 'em']),
    avatar: safeComment.avatar ? safeDisplay.url(safeComment.avatar) : null
  };
}

// Form data processing
function processContactForm(formData: Record<string, any>) {
  const sanitized = sanitizeObject(formData);
  
  return {
    name: safeDisplay.text(sanitized.name),
    email: safeDisplay.text(sanitized.email),
    message: safeDisplay.text(sanitized.message),
    website: sanitized.website ? safeDisplay.url(sanitized.website) : ''
  };
}

Content Management Systems

// Rich text editor content
function renderArticle(article: { title: string; content: string; excerpt: string }) {
  const allowedTags = [
    'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
    'strong', 'em', 'u', 'ol', 'ul', 'li',
    'blockquote', 'a', 'br', 'hr'
  ];
  
  return {
    title: safeDisplay.text(article.title),
    content: safeDisplay.html(article.content, allowedTags),
    excerpt: safeDisplay.text(article.excerpt)
  };
}

API Response Sanitization

import { sanitizeObject } from 'xss-safe-display';

// Sanitize API responses
async function fetchUserData(userId: string) {
  const response = await fetch(`/api/users/${userId}`);
  const userData = await response.json();
  
  // Sanitize all string fields in the response
  return sanitizeObject(userData);
}

Security Best Practices

1. Defense in Depth

Always sanitize at multiple layers:

// At input (form submission)
const sanitizedInput = sanitizeObject(formData);

// At storage (before database)
const cleanData = sanitizeString(sanitizedInput.content);

// At display (before rendering)
const displayContent = safeDisplay.text(cleanData);

2. Allowlist Approach

Always use allowlists for HTML tags:

// ✅ Good - explicit allowlist
const allowedTags = ['p', 'strong', 'em', 'ul', 'ol', 'li'];
safeDisplay.html(content, allowedTags);

// ❌ Avoid - no restrictions
safeDisplay.html(content); // May allow dangerous tags

3. Content Security Policy (CSP)

Combine with CSP headers for additional protection:

<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self';">

4. Input Validation

Validate data types and formats:

function validateAndSanitize(input: unknown): string {
  if (typeof input !== 'string') {
    throw new Error('Invalid input type');
  }
  
  if (input.length > 10000) {
    throw new Error('Input too long');
  }
  
  return safeDisplay.text(input);
}

TypeScript Support

Full TypeScript definitions included:

interface SafeDisplay {
  text(value: string | number | undefined | null): string;
  html(content: string, allowedTags?: string[]): { __html: string };
  url(url: string): string;
}

declare function sanitizeString(input: string): string;
declare function sanitizeHTML(content: string, allowedTags?: string[]): string;
declare function sanitizeObject<T>(obj: T): T;
declare function escapeHTML(text: string): string;
declare function sanitizeUrl(url: string): string;
declare const safeDisplay: SafeDisplay;

Browser Support

  • ✅ Chrome 60+
  • ✅ Firefox 55+
  • ✅ Safari 12+
  • ✅ Edge 79+
  • ✅ Node.js 12+

Performance

  • Lightweight bundle size (~15kb minified)
  • Tree-shakable exports
  • Zero external dependencies
  • Optimized for frequent sanitization operations

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Testing

npm test
npm run test:coverage
npm run test:security

License

MIT © [Your Name]

Changelog

v1.0.0

  • Initial release
  • Core sanitization functions
  • safeDisplay utilities
  • TypeScript support
  • React integration examples

Support