Skip to content

Latest commit

 

History

History
366 lines (279 loc) · 8.25 KB

File metadata and controls

366 lines (279 loc) · 8.25 KB

Examples

This directory contains practical examples of how to use react-secure-html in real-world scenarios.

📁 Examples Structure

examples/
├── basic-usage/           # Basic component usage
├── blog-post/            # Blog post renderer
├── user-comments/        # User comment system
├── rich-text-editor/     # Rich text editor preview
├── email-template/       # Email template renderer
├── cms-content/          # CMS content display
├── markdown-renderer/    # Markdown to HTML renderer
└── security-demo/        # Security demonstration

🚀 Quick Examples

Basic HTML Rendering

import { SafeHTML } from 'react-secure-html';

function BasicExample() {
  return <SafeHTML content="<p>Hello <strong>World</strong>!</p>" allowHTML />;
}

User Comments

import { SafeHTML } from 'react-secure-html';

function Comment({ text, author }: { text: string; author: string }) {
  return (
    <div className="comment">
      <div className="comment-author">{author}</div>
      <SafeHTML content={text} allowHTML className="comment-content" />
    </div>
  );
}

Blog Post Renderer

import { SafeHTML } from 'react-secure-html';

function BlogPost({ content, title }: { content: string; title: string }) {
  return (
    <article className="blog-post">
      <h1>{title}</h1>
      <SafeHTML content={content} allowHTML tag="div" className="prose prose-lg max-w-none" />
    </article>
  );
}

Rich Text Editor Preview

import { useSanitize } from 'react-secure-html';

function RichTextPreview({ content }: { content: string }) {
  const { sanitizeHTML } = useSanitize();

  return (
    <div
      className="preview"
      dangerouslySetInnerHTML={{
        __html: sanitizeHTML(content, {
          ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'a', 'ul', 'ol', 'li'],
          ALLOWED_ATTR: ['href', 'class'],
        }),
      }}
    />
  );
}

Email Template

import { SafeHTML } from 'react-secure-html';

function EmailTemplate({ html }: { html: string }) {
  return (
    <div className="email-template">
      <SafeHTML content={html} allowHTML tag="div" className="email-content" />
    </div>
  );
}

CMS Content Display

import { SafeHTML } from 'react-secure-html';

function CMSContent({ content, type }: { content: string; type: 'html' | 'text' }) {
  return <SafeHTML content={content} allowHTML={type === 'html'} className="cms-content" />;
}

Markdown Renderer

import { SafeHTML } from 'react-secure-html';
import { marked } from 'marked';

function MarkdownRenderer({ markdown }: { markdown: string }) {
  const html = marked(markdown);

  return <SafeHTML content={html} allowHTML className="markdown-content" />;
}

🔒 Security Examples

XSS Prevention Demo

import { SafeHTML } from 'react-secure-html';

function SecurityDemo() {
  const maliciousContent = `
    <script>alert('XSS Attack!')</script>
    <img src="x" onerror="alert('XSS')">
    <a href="javascript:alert('XSS')">Click me</a>
    <p>Safe content</p>
  `;

  return (
    <div>
      <h2>Security Demo</h2>
      <h3>Malicious Content:</h3>
      <pre>{maliciousContent}</pre>

      <h3>Safe Rendering:</h3>
      <SafeHTML content={maliciousContent} allowHTML className="security-demo" />
    </div>
  );
}

URL Sanitization

import { sanitizeURL } from 'react-secure-html';

function URLDemo() {
  const urls = [
    'https://example.com',
    'javascript:alert("xss")',
    'data:text/html,<script>alert("xss")</script>',
    'mailto:test@example.com',
  ];

  return (
    <div>
      <h2>URL Sanitization Demo</h2>
      {urls.map((url, index) => (
        <div key={index}>
          <strong>Original:</strong> {url}
          <br />
          <strong>Sanitized:</strong> {sanitizeURL(url) || '(blocked)'}
        </div>
      ))}
    </div>
  );
}

🎨 Styling Examples

With Tailwind CSS

import { SafeHTML } from 'react-secure-html';

function StyledContent({ content }: { content: string }) {
  return (
    <SafeHTML
      content={content}
      allowHTML
      className="prose prose-lg max-w-none prose-headings:text-gray-900 prose-p:text-gray-700"
    />
  );
}

With CSS Modules

import { SafeHTML } from 'react-secure-html';
import styles from './Content.module.css';

function ContentWithModules({ content }: { content: string }) {
  return <SafeHTML content={content} allowHTML className={styles.content} />;
}

🔧 Advanced Usage

Custom Sanitization

import { useSanitize } from 'react-secure-html';

function CustomSanitization({ content }: { content: string }) {
  const { sanitizeHTML } = useSanitize();

  const customSanitized = sanitizeHTML(content, {
    ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'a', 'img'],
    ALLOWED_ATTR: ['href', 'src', 'alt', 'class'],
    ALLOW_DATA_ATTR: false,
    ADD_ATTR: ['target'], // Allow target attribute
  });

  return <div dangerouslySetInnerHTML={{ __html: customSanitized }} />;
}

Conditional Rendering

import { SafeHTML } from 'react-secure-html';

function ConditionalContent({ content, isTrusted }: { content: string; isTrusted: boolean }) {
  return (
    <SafeHTML
      content={content}
      allowHTML={isTrusted}
      className={isTrusted ? 'trusted-content' : 'untrusted-content'}
    />
  );
}

Performance Optimization

import { SafeHTML } from 'react-secure-html';
import { memo } from 'react';

const OptimizedContent = memo(({ content }: { content: string }) => {
  return <SafeHTML content={content} allowHTML className="optimized-content" />;
});

OptimizedContent.displayName = 'OptimizedContent';

📱 Framework Examples

Next.js

// pages/blog/[slug].tsx
import { SafeHTML } from 'react-secure-html';
import { GetStaticProps } from 'next';

export default function BlogPost({ post }: { post: any }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <SafeHTML content={post.content} allowHTML className="prose" />
    </article>
  );
}

export const getStaticProps: GetStaticProps = async ({ params }) => {
  // Fetch post data
  return {
    props: { post: {} },
  };
};

Remix

// app/routes/blog.$slug.tsx
import { SafeHTML } from 'react-secure-html';
import { useLoaderData } from '@remix-run/react';

export default function BlogPost() {
  const { post } = useLoaderData();

  return (
    <article>
      <h1>{post.title}</h1>
      <SafeHTML content={post.content} allowHTML className="prose" />
    </article>
  );
}

🧪 Testing Examples

Component Testing

import { render, screen } from '@testing-library/react';
import { SafeHTML } from 'react-secure-html';

describe('SafeHTML Component', () => {
  it('renders HTML content safely', () => {
    render(<SafeHTML content="<p>Hello <strong>World</strong></p>" allowHTML />);

    expect(screen.getByText('Hello')).toBeInTheDocument();
    expect(screen.getByText('World')).toBeInTheDocument();
  });

  it('escapes dangerous content', () => {
    render(<SafeHTML content="<script>alert('xss')</script>" allowHTML />);

    expect(screen.queryByText("alert('xss')")).not.toBeInTheDocument();
  });
});

Hook Testing

import { renderHook } from '@testing-library/react';
import { useSanitize } from 'react-secure-html';

describe('useSanitize Hook', () => {
  it('sanitizes HTML content', () => {
    const { result } = renderHook(() => useSanitize());

    const sanitized = result.current.sanitizeHTML('<script>alert("xss")</script>');
    expect(sanitized).not.toContain('<script>');
  });

  it('escapes HTML entities', () => {
    const { result } = renderHook(() => useSanitize());

    const escaped = result.current.escape('<>&"\'');
    expect(escaped).toBe('&lt;&gt;&amp;&quot;&#39;');
  });
});

📚 More Examples

For more examples, check out:

🤝 Contributing Examples

Have a great example? We'd love to see it! Please:

  1. Fork the repository
  2. Add your example to the examples/ directory
  3. Update this file
  4. Submit a pull request

Happy coding! 🚀