typography.js
typography.js copied to clipboard
react-typography and create-react-app
I'm trying to use react-typography in a create-react-app based application.
In CRA there is no such thing as index.js that readme mentions, and I don't understand how to add <TypographyStyle> and <GoogleFont> to the <head> of index.html.
I tried
function App() {
return (
<React.Fragment>
<Helmet>
<TypographyStyle typography={typography} />
<GoogleFont typography={typography} />
</Helmet>
... my app here ...
</React.Fragment>
but it didn't work and produced You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information. in the console.
Without <Helmet> it works, but <link> and <style> happen to be in the <body> (that's expected, and not good).
CRA is probably the most common way to bootstrap react apps, so this issue should be addressed in the readme.
Injecting <TypographyStyle> does work by means of typography.injectStyles(), as mentioned in the readme. Similar inject method is missing for google fonts, and I resorted to copying <link> from google fonts website to public/index.html. It's not elegant, because I have to keep in sync google fonts I declare in new Typography({...}) with fonts I load in <link>.
I guess injectStyles method could be modified to receive an options object with googleFonts property of true or false: typography.injectStyles({googleFonts: true}). If it's true, google font's <link> would be injected in <head> along with <style> tag of typography.js.
@mvasin i imagine you've come up with something better by now, BUT: I came across this googling for answers. I couldn't find anything better, so I hacked together the following solution:
https://github.com/dradetsky/typography-inject-fonts
Basically, you add another line injectFonts(typography). It at least initially appears to work (famous last words).
I'll sort out npm publication later; gotta get to a job interview soon. In the meantime, I suppose you could tell me any obvious mistakes I've made (you may find /bin/cat helpful here).
@KyleAMathews pinging you in case you want to mark this as solved, or even (ha ha) mention it in the readme.
@dradetsky this is great! Could you PR it to the README once you've got the NPM publication completed?
@KyleAMathews yeah, i just added it. I'll write something up & PR it soon.
FWIW, a much better solution would be if you (or somebody else who knows how to do this sort of thing properly) made a create-react-app template which has an index.js/html.js root instead of being injected into a root element of the base index.html. That would (I think) make OP's solution work. Then you could just say "Create React App: Use the X template, it'll make things easier. If you can't, here's an ugly hack that may help:"
BTW, I originally started to use ~~typescript.js~~ typography.js just to find an easy way to make my app look halfway decent, which isn't even a major requirement to begin with (it's basically a clone of Dash.app that runs in the browser). The easiest way to do that was to use one of your default typeography themes, but then I had to get the google fonts to work, and this was the easiest way to make that happen.
But it turns out there was an even easier way: just use typefaces-open-sans. Now the hack is no longer necessary. This method also provides self-hosting, which is even better for my app. Not only is erroring on caltrain undesirable, super-high responsiveness is a major requirement. It's one of the reasons I consider reading the docs off the filesystem instead of off the internet basically essential.
So basically, I've abandoned the solution myself (not that it doesn't appear to work). I'm also thinking I should add something like "But you could also just use Open Sans" to my readme PR. Maybe that will seem like a pretty extreme response to a typical font-obsessed frontend designer, but it's exactly what I would have wanted to see.
Not trying to resurrect this, but I got this working with react-helmet like this (in Typescript):
import React from 'react';
import { Helmet, HelmetProps } from 'react-helmet';
import typography from '../../util/typography'; // my exported theme
export const Head: React.FC<HelmetProps> = props => {
const { children, ...rest } = props;
// Create family + styles string
let fontsStr = '';
if (typography.options.googleFonts) {
const fonts = typography.options.googleFonts.map(font => {
let str = '';
str += font.name.split(' ').join('+');
str += ':';
str += font.styles.join(',');
return str;
});
fontsStr = fonts.join('|');
}
return (
<Helmet {...rest}>
{fontsStr !== '' && (
<link
href={`//fonts.googleapis.com/css?family=${fontsStr}`}
rel="stylesheet"
type="text/css"
/>
)}
<style>{`${typography.createStyles()}`}</style>
{children}
</Helmet>
);
};
Then, I can just use <Head> instead of <Helmet>:
import React from 'react';
import { Head } from '../MetaComponents/Head';
export const HomePage: React.FC = props => {
return (
<div>
<Head>
<title>Nathan Smith</title>
</Head>
<h1>Hello World</h1>
</div>
);
};
The secret sauce is (for some reason) putting in the styles as a template rather than using children or dangerouslySetInnerHTML.
import { GoogleFont } from "react-typography";
<GoogleFont typography={typography} />
This will work by just artificially dumping the <link for 'Google fonts.'
From here, you can clean it up by just cutting this link and then placing it in the 'public/index.html' so it's in <head> like supposed to be.
From there, just remove the 'react-typography' and <GoogleFont> and all still works.
Of course, if you change themes, you have to do this again.