9

Our application is build using Material-UI library (with themes). As part of this app we are parsing markdown to html (marked library).

How can you apply material-ui themes ( Typography ) to a pure html ?

Somehow

<div dangerouslySetInnerHTML={ {__html: marked(markdown code)}}/>

Should have the styles as defined by material-ui Typography

ic3
  • 7,917
  • 14
  • 67
  • 115
  • Is there any reason you chose `marked` over a react specific library that has easier support for this? – Jacob Smit Feb 14 '21 at 21:05
  • @JacobSmit , no reason. But I don't want a library that adds a lot of react nodes as content is 'static'. – ic3 Feb 15 '21 at 07:36
  • Fair enough. As a piece of interest then, one of the co-founders of Material UI answered a question about markdown and typography before and linked to an example of how they are (or at least were) handling the markdown for the documentation website. https://github.com/mui-org/material-ui/issues/12290#issuecomment-453930042 – Jacob Smit Feb 15 '21 at 20:14
  • @JacobSmit , that helps . thanks. Looks as it's a 'manual' work – ic3 Feb 17 '21 at 07:25

3 Answers3

14

The styles for all the Typography variants are in the theme at theme.typography.<variant> (you can browse those entries in the default theme here: https://material-ui.com/customization/default-theme/#default-theme). You can leverage this to create styles to target the tags you want to support as shown in the example below:

import React from "react";
import { makeStyles } from "@material-ui/core";
import Typography from "@material-ui/core/Typography";

const useStyles = makeStyles((theme) => {
  const tags = ["h1", "h2", "h3", "h4", "h5", "h6"];
  const nestedRules = {};
  tags.forEach((tag) => {
    nestedRules[`& ${tag}`] = { ...theme.typography[tag] };
  });
  return {
    root: nestedRules
  };
});

export default function App() {
  const classes = useStyles();
  return (
    <Typography
      className={classes.root}
      variant="body1"
      dangerouslySetInnerHTML={{
        __html:
          "<h1>H1</h1><h2>H2</h2><h3>H3</h3><h4>H4</h4><h5>H5</h5><h6>H6</h6><p>default body1</p>"
      }}
    ></Typography>
  );
}

Edit style html tags

Related answer: material-ui makeStyles: how to style by tag name?

Ryan Cogswell
  • 75,046
  • 9
  • 218
  • 198
5

use regular Typography component and pass that HTML in a similar way as it is passed in the question.

<Typography
    variant="h2"
    color="primary"
    dangerouslySetInnerHTML={{ __html: "<p>Hi from inner HTML</p>" }}>
    
</Typography>

One catch is here that when dangerouslySetInnerHTML is passed then don't pass anything as children.

Here is a working demo :

Edit nervous-cookies-nedrz

Note: Also make sure that the function marked(markdown code) returns the HTML in string.

Rajiv
  • 3,346
  • 2
  • 12
  • 27
  • This might works with a single tag, but doesn't work with multiple ones (h1,h2.. ) -> https://codesandbox.io/s/dazzling-wildflower-p6dvq .. check how the styles are generated. – ic3 Feb 03 '21 at 14:23
  • I guess it is working as the color and font family of h2 variant is getting applied. Of what part you think this is not working? – Rajiv Feb 03 '21 at 14:41
  • is it bcoz of fontSize? – Rajiv Feb 03 '21 at 14:42
  • You expect the html inside h1 to use variant h1, the html inside h3 to use variante h3.. it's not the case. – ic3 Feb 03 '21 at 14:48
1

Use the markdown-to-jsx npm package. here is the example from the material ui templates.

You basically have to create a config object that ReactMarkdown likes, that is specific for material ui

import React from 'react';
import ReactMarkdown from 'markdown-to-jsx';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Link from '@material-ui/core/Link';

const styles = (theme) => ({
  listItem: {
    marginTop: theme.spacing(1),
  },
});

const options = {
  overrides: {
    h1: {
      component: Typography,
      props: {
        gutterBottom: true,
        variant: 'h5',
      },
    },
    h2: { component: Typography, props: { gutterBottom: true, variant: 'h6' } },
    h3: { component: Typography, props: { gutterBottom: true, variant: 'subtitle1' } },
    h4: {
      component: Typography,
      props: { gutterBottom: true, variant: 'caption', paragraph: true },
    },
    p: { component: Typography, props: { paragraph: true } },
    a: { component: Link },
    li: {
      component: withStyles(styles)(({ classes, ...props }) => (
        <li className={classes.listItem}>
          <Typography component="span" {...props} />
        </li>
      )),
    },
  },
};

export default function Markdown(props) {
  return <ReactMarkdown options={options} {...props} />;
}

I got that straight from their example.

Zachiah
  • 1,750
  • 7
  • 28