If you want to use Material Icons on your webpage, it’s advised that you stick a <link> tag in your HTML like so:
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/>
But what if you want to check if Material Icons is already included on the page and then load it if it’s not? (all via JavaScript, of course)
Here’s an example use case: you provide a library which leverages Material Icons. Rather than instruct the consumer that they have to stick a <link> tag in their header and then use the icon, just tell them to use the icon and under the hood you take care of whether the material icons dependency is loaded.
Here’s a basic implementation example (concept borrowed from this post):
let $span = document.createElement("span");
$span.className = "material-icons";
$span.style.display = "none";
document.body.insertBefore($span, document.body.firstChild);
const needToLoadMaterialIcons =
window.getComputedStyle($span, null).getPropertyValue("font-family") !==
"Material Icons";
if (needToLoadMaterialIcons) {
let $link = document.createElement("link");
$link.href = "https://fonts.googleapis.com/icon?family=Material+Icons";
$link.rel = "stylesheet";
document.head.appendChild($link);
}
document.body.removeChild($span);
Let’s take it a step further. Say you’re creating a component library in React and you provide a component where consumers can pass you the name of the material icon they want to display, i.e. <Icon name="calendar" />. Rather than tell the consumer “hey, before you use this library, make sure you put a <link> in your app to load the Material Icons font family”, you could check to see if the font is already in the DOM by doing a check inside componentDidMount().
Granted, using the code above in a componentDidMount() is less than ideal from a performance perspective. That’s a lot of code to execute every time an <Icon /> component is mounted to the DOM. However, you could get around this by setting a boolean flag on the window so that the very first time any <Icon /> component is used from your library, your library will ensure Material Icons has loaded. Then, after this first usage, every subsequent <Icon /> component is only checking a boolean flag (which is more inexpensive from a performance perspective). Here’s a basic example:
export default class Icon extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
if (window.I_HAVE_TRIED_TO_LOAD_MATERIAL_ICONS) {
return;
}
window.I_HAVE_TRIED_TO_LOAD_MATERIAL_ICONS = true;
if (
window
.getComputedStyle(this.iconRef.current, null)
.getPropertyValue("font-family")
.indexOf("Material Icons") === -1
) {
let $link = document.createElement("link");
$link.href = "https://fonts.googleapis.com/icon?family=Material+Icons";
$link.rel = "stylesheet";
document.head.appendChild($link);
}
}
render() {
return (
<i className="material-icons" ref={this.myRef}>
{this.props.name}
</i>
);
}
}
There’s some more sophistication that could go into this, like avoiding FOUT, but I think the general idea is here as a foundation if you wanted to give it a shot.