Home > other >  Pass HTML into custom Component
Pass HTML into custom Component

Time:11-19

I've created a custom component to simply layout content inside IonCardContent. This works great for my needs so far:

interface ContainerProps {
    position?: string;
    content?: string,
    colour?: string;
    custClass?: string;
}

const CardContainer: React.FC<ContainerProps> = ({ position = "right", content = "n/a", colour = "", custClass = "" }) => {
    
    if ( position.trim().toLowerCase() === "right" ) {
        return <><div className={"ion-float-right "   custClass} >{content}</div><div className="clear-right"></div></>
    } else if ( position.trim().toLowerCase() === "left" ) {
        return <div className={"ion-float-left "   custClass}>{content}</div> 
    } else if ( position.trim().toLowerCase() === "full" ) {
        return <div className={""    custClass}>{content}</div>
    } else if ( position.trim().toLowerCase() === "empty" ) { 
        return <div className={""    custClass}>&nbsp;</div> 
    } else {
        return null
    }  
};

export default CardContainer;

However, I'd now like to start passing in some html elements to the component so I can do things like highlight sections of text by making it bold or by wrapping part of the string in a span and adding a css class to it.

At present, adding html to the content attribute just results in this being displayed as a literal string. This is obviously due to "content" being declared as a string.

Is the solution to displaying html simply changing the type declaration in the Interface? If so, what to? Or is a more complex solution required?

Thanks.

CodePudding user response:

From the duplicate answer in comments:

import sanitizeHtml from 'sanitize-html';

const MyComponent = () => {
  dirty = '<a href="my-slug" target="_blank" onClick="evil()">click</a>';
  const clean = sanitizeHtml(dirty, {
    allowedTags: ['b', 'i', 'em', 'strong', 'a'],
    allowedAttributes: {
      a: ['href', 'target']
    }
  });
  return (
    <div 
      dangerouslySetInnerHTML={{__html: clean}}
    />
  );
};

therefore

import sanitizeHtml from 'sanitize-html';

interface ContainerProps {
    position?: string;
    content?: string,
    colour?: string;
    custClass?: string;
}

 const CardContainer: React.FC<ContainerProps> = ({ position = "right", 
 content = "n/a", colour = "", custClass = "" }) => {

const myHTML = null;
    
    if ( position.trim().toLowerCase() === "right" ) {
        myHTML = '<div className={"ion-float-right "   custClass} >{content}</div><div className="clear-right"></div>'
    } else if ( position.trim().toLowerCase() === "left" ) {
        myHTML = '<div className={"ion-float-left "   custClass}>{content}</div>' 
    } else if ( position.trim().toLowerCase() === "full" ) {
        myHTML = '<div className={""    custClass}>{content}</div>'
    } else if ( position.trim().toLowerCase() === "empty" ) { 
        myHTML = '<div className={""    custClass}>&nbsp;</div>'
    }

 const clean = sanitizeHtml(myHTML, {
    allowedTags: ['b', 'i', 'em', 'strong', 'a'],
    allowedAttributes: {
      a: ['href', 'target']
    }
  });
  return (
    <div 
      dangerouslySetInnerHTML={{__html: clean}}
    />
  );
};

export default CardContainer;

You will of course need to adjust the allowedTags and allowedAttribute values to suit your needs

CodePudding user response:

Passing all my html output plus dynamic content passed in via variable, into the santizer meant that the variables were either stripped out or their calls were displayed as literal markup.

Therefore, it was necessary to just sanitize the variable that contained the html content passed to the component.

import React from 'react';
import './CardContainer.css';
import sanitizeHtml from 'sanitize-html';

interface ContainerProps {
    position?: string;
    content?: string,
    colour?: string;
    custClass?: string;
}

const CardContainer: React.FC<ContainerProps> = ({ position = "right", content = "n/a", colour = "", custClass = "" }) => {
    
    const clean = sanitizeHtml(content, {
        allowedTags: ['b', 'i', 'em', 'strong', 'a', 'div', 'span'],
        allowedAttributes: {
          a: ['href', 'target'],
          div: ['class', 'className'],
          span: ['style', 'class', 'className']
        }
    });
    


    if ( position.trim().toLowerCase() === "right" ) {
        return <><div className={"ion-float-right "   custClass} dangerouslySetInnerHTML={{__html: clean}}/><div className="clear-right"></div></>
    } else if ( position.trim().toLowerCase() === "left" ) {
        return <div className={"ion-float-left "   custClass} dangerouslySetInnerHTML={{__html: clean}}/>
    } else if ( position.trim().toLowerCase() === "full" ) {
        return <div className={""    custClass} dangerouslySetInnerHTML={{__html: clean}}/>
    } else if ( position.trim().toLowerCase() === "empty" ) { 
        return <div className={""    custClass}>&nbsp;</div> 
    } else {
        return null
    }  
};

export default CardContainer;
  • Related