labs-description.tsx 1.0 KB

1234567891011121314151617181920212223242526272829303132333435363738
  1. import { FC, useMemo } from 'react'
  2. import { micromark } from 'micromark'
  3. import DOMPurify from 'dompurify'
  4. const PURIFY_CONFIG = {
  5. ALLOWED_TAGS: ['#text', 'p', 'em', 'strong', 'a'],
  6. ALLOWED_ATTR: ['href'],
  7. }
  8. const LINK_REL = 'noreferrer noopener'
  9. const LINK_TARGET = '_BLANK'
  10. function sanitizeDescription(description: string) {
  11. DOMPurify.addHook('afterSanitizeAttributes', node => {
  12. if (node.nodeName === 'A') {
  13. node.setAttribute('rel', LINK_REL)
  14. node.setAttribute('target', LINK_TARGET)
  15. }
  16. })
  17. try {
  18. return DOMPurify.sanitize(micromark(description), PURIFY_CONFIG)
  19. } finally {
  20. DOMPurify.removeHook('afterSanitizeAttributes')
  21. }
  22. }
  23. /**
  24. * Renders a labs experiment description from markdown to sanitized HTML.
  25. * Only bold, italic, and links are supported.
  26. */
  27. export const LabsDescription: FC<{ description: string }> = ({
  28. description,
  29. }) => {
  30. const html = useMemo(() => sanitizeDescription(description), [description])
  31. return <div dangerouslySetInnerHTML={{ __html: html }} />
  32. }