Add LaTex to WeWeb with MathJax

Ray Deck shows how to render LaTeX formulas in WeWeb using MathJax v3. He loads the script via custom code, accesses the MathJax object through wweblib.getFrontWindow, and calls the typeset function after content updates. A timed delay ensures the library loads before the DOM renders, letting users enter and display math formulas dynamically.
Chapters
Today's challenge comes from Rish Dvn over on the WeWeb community who has the challenge of wanting to implement a LaTeX encoding and display on their WeWeb application. Now the way they're going to do this is using a library, as you can sort of see in here, called mathml. MathJax. So let's learn a little bit more about how to do that and how we can get layout of cool mathematical formulas going directly inline into your WeWeb application. So if I just Google up MathJax, I can, you know, go find it and here's mathjax.org. Excellent. So this is the idea behind MathJax. MathJax uses this encoding called LaTeX, which allows you to define using relatively ordinary characters, you know, backslash and all these things here. And turn them into like these mathematical, you know, symbolic representations, like the kinds of things you would see in a very cryptic math paper or an AI paper or what have you. And it can look very nice. And then the idea is then you can just put in the text and then MathJax takes care of laying everything out to turn it into this more complicated mathematical formulae. The question becomes, how do we do that in WeWeb? And how do we bring it to the party? And so we can start to search through and look at this documentation. And really what I look for is, da da da da, here's some web integration, okay? And we can have some, you know, MathJax. Ah, here we can have some version 3 going on to it, all right? And, do do do do do do, and then, and then this seems like a, a good place to, to start. So the key is this is going to use MathJax version 3 because that actually is the current version of MathJax. I'm pretty sure. So we go take a look at the documentation, we will see that, oh yeah, here it is. See version 3.0 of MathJax. That's gonna be the latest documentation and that's, or the latest version of MathJax. And that's what they're going to talk about in the documentation as well as in the tutorials. This is significant because the original request was using something maybe from like ChatGPT or something that was referencing an old version of MathJax. You see 2.7, which is going to have a different API than the newer version. So one of the first things we're gonna want to do is bring the new version of MathJax into WeWeb. Now to do that, let's go into WeWeb and let's make a new project in WeWeb and we'll say select, fine. And we'll call it, you know, latex, you know, YT for YouTube. And we will open this up in the editor. And, you know, we're just gonna start with like, how do we have the text that would be for LaTeX? And we'll go add and we'll say elements. And in the elements, I have a paragraph here. That's usually the way we do ordinary text. And you can see how it looks all like this stuff, fine. And we can copy over, you know, the example LaTeX, you know, bit they've gotten here, copy that. Great. And we'll put this into that, into the LaTeX YT. And if I just triple-click here and paste, it will just put it directly into the text. And you can see that in WeWeb, we have that text. Let's not be converted into LaTeX. Now, for you to bring in this kind of external library into WeWeb, there are a couple different ways of doing it. One way to do it that's probably good for production but not so good for testing is we can add it as a custom code that would go on our page. We can go over to page and, you know, the variables on it, we can add custom code like to the header. And that usually is a good place to add a script tag directly that you want to have for publication. That's really a pain to develop on. So what I like to do is go find, and we can load and configure MathJax and go find, you know, okay, where the script tag is that we can load in MathJax version 3. And there is a tool that we create over at StateChange called WeWeb Embed that will take this kind of script tag and put it into a JavaScript action so that you can just use it inside the WeWeb editor, which allows for a very fast learning loop. So we're gonna go take this, we're gonna copy the script tag that goes along with MathJax. Now you'll notice this example here is actually suggesting we should use multiple ways of pulling things in. You can configure MathJax to have, you know, the additional configurations. We're not gonna worry about that part just yet. We're just gonna say, let's load MathJax with whatever its defaults are. And to do that, we can just paste that. Just as easily, by the way, we could, if we wanted to, take the whole thing, copy that, and put this into, you know, the, the WeWeb embedder, whatever that source is, whatever you want to do will work. But So what I'm going to do right now is just copy the basic and paste. And when I do that, I can convert these into WeWeb action and you can see that it will automatically create JavaScript that will inline, you know, create the script element on the page, load in and load in the, the code that goes along with it. So I can click on copy code to clipboard, go back over to WeWeb and say that instead of adding custom code, I'm going to trigger a workflow because Workflows will fire in the editor, whereas custom code will not. Custom code requires us to press the publish button over here. So we can say add a workflow, and we will say add an action, and, uh, the action's going to be a JavaScript action, which is a key thing because, uh, this is code that is not about WeWeb formula. We're bringing alien code to the party. And to do that, we just click into here and press paste. Done. And now we have loaded LaTeX into our page. And we have the code into here. So what should happen then is I load the page and the LaTeX code, the, the MathJax will load in and by default it will automatically take whatever's currently on the page and it will format anything that is LaTeX into LaTeX. So let's run this and let's try pushing the refresh button. And you know what? It doesn't work so well. And the reason it doesn't work well is because a lot of these script tag based approaches are, have the idea that you're talking to HTML that's being built on a page statically as opposed to something that's dynamic like in WeWeb where, you know, the strings we're looking at on the page can be created at some time after that the original page loads. So in order for us to be able to have something that's going to modify this stuff as we see it here, we're gonna need to have a little bit of time delay between when the original library loads and when we want the MathJax to actually work. To do that, we're gonna need to find a function to work with. So let me show you how I would investigate MathJax for this job. We're going to use DevTools in the browser and go to console. Console here, good, good, good. There's lots of stuff in here, don't worry about too much. The, but really what we can do is we can use dub dub lib which is the core library for WeWeb, dot, um, uh, the, the, um, you know, get front window. And this is important because you don't want to just use the, um, the, the, the global window object necessarily when you're in WeWeb, because since WeWeb, uh, particularly in editor runs inside an iframe, the top window might not be the same as the window that's the context for WeWeb itself. So using wweblib.get front window can be really, really helpful. So if I just press Enter here, I get to find out what everything is thinking about, but I know that inside it there's something called MathJax. So cool, right? And now by just doing MathJax, I can enumerate it, which means being able to take a look at what's inside it. Pressing Enter then gives me a thing, a little triangle here. I can open it up and see all the different functions and properties it has. Like I can see what its configuration was, but most importantly, I can see its functions. And one of those functions, its core function in fact, is called typeset. Typeset is a function that it runs automatically on startup. Is this, is this function that causes it to take the text that sees directly on the page and turn it into that nice mathematical function that you saw before. So in fact, I can, I could run that right now. I can say mathjax.typeset, even directly from DevTools like this, and you can see how it immediately changed the thing that we see over here on the left. So now that we know that's actually the correct line, I'm going to go copy that, copy that. You don't need to do this yourself when you're, you know, implementing this in your own environment, but this is a pretty good diagnostic technique and kind of fun. And now what we need to do is get our startup process to actually trigger workflows and on the page load, we want to actually run that code after we've loaded up the MathJax stuff. So basically this is responsible for bringing MathJax into the page. And then we want subsequent to that to, you know, run the JavaScript line that we just created, which is going to be lib.getFrontWindow, MathJax, typeset. But this probably doesn't solve anything because these two are gonna run so fast next to each other that the timing problem I was talking about, it will run in sequence, but not with any delay. So we can introduce a delay by pressing plus here and saying time delay. And we can introduce a delay of, I'll call it, I don't know, 3,000 milliseconds. All right. And what that will do is take, spend 3 seconds. So it will initially load in the MathJax library, try to do a thing, wait 3 seconds, and then update. Anything else I need to typeset right now? And they will take care of it for us. So let's close that and we will close that. And then we can say, well, let's try refreshing the page. We see our ordinary text and a couple seconds later shows the good text. Now dialing in how long you want to delay this is kind of up to you. And there are a couple ways we can make that, you know, a little bit more tied to the way the WeWeb development cycle works. But as a first approximation, this is a decent way for data that you know is there at the beginning of the page to get displayed. Now, as you might already be guessing, you don't have to only run typeset when the page loads. You have to import typeset, import MathJax, um, from Cloudflare or whatever the original library was, um, at the start of the page runtime, but then we can run typeset whenever you want over the course of the page lifetime. And that means we can do it dynamically, which is also kind of a fun thing. So let's bring some interesting new complexity to the party. Let's say we're going to have an input and we will call it, you know, long answer. No, I didn't want email. Let's do a plus and we'll input control and we'll grab the long answer. Great. Just so we can have something expansive that we can be writing into. And then we'll also add a button. Mm-hmm. And we're going to do one more thing too. We're going to say that this, instead of being hardcoded to text, which it currently is, we're going to tell it to please work with a variable and we're gonna create new variable and the variable's going to be called LaTeX text and you know, no folder for it. And we're gonna say it's gonna be a string and it'll have no default value and that's fine. And then we'll just say create that, that variable won't do anything for us at the beginning. But what we're going to do is we're going to bind this set, this initial string to the variable that we call latex test. Great. Okay. So now as you can see, it's not actually showing anything. So let's, and now what I'm also going to do is take the button and I'm going to add a workflow so that on the click, we're going to change a variable value to say that the text parameter should now be equal to whatever was in the long answer. So that way I can type in the long answer and then press the button and then that will set the text in LaTeX to be whatever we need it to be. So let's, you know, close this and try just putting ourselves into play for this. So we'll just say, hello world, this is Ray and click. You see, so it's hello world, this is Ray and, and this is my function. And then I'm just going to copy in his function here. Let's, right here. And you can see that if I paste that into my, you know, the long answer, you know, it just updates the paragraph that I already had at the top with this additional text. Now that shows that I can control that through whatever I have in the input., but you also see that it didn't actually do any layout for me. But this is actually where we get to the cool part because I can click into the click me, I can go into the workflow and then after changing the variable value, I can go run typeset again. Going down to custom JavaScript. Uh-huh. I'm going to say www.lib.getFrontWindow, open, close,.mathjax, typeset, right? Just like we did at the very beginning of PageRuntime, the thing that had like 3-second delay to it. All right. So what this will do then is update the, you know, update my, the paragraph to have the text that I put into the long answer into the input and then typeset it with LaTeX. Let's see how that works. Uh-huh. And then let's try running that. Stick with me. Oh, look at that. And function if you please. And then what if I didn't want to have, do, do, do, do, do. Let's see if I want to be inline, I think I use parentheses instead of square brackets. You can check me on that. Parenthesis, parenthesis. Yeah, see, and then that does a little more inline. Now, the point of this exercise is not to teach you how to do LaTeX and like square brackets and the parentheses and how those differences and those things work. But, you know, you can look up how to be using LaTeX, but what this will do is bring whatever LaTeX you have in your text. This could be coming from data you have in your backend. This could be coming from data I typed in. This could be coming from things you have statically on your page. But now you have the ability to lay out your LaTeX wherever it is you want on the page. All you need to do is make sure that you have first imported the MathJax at the beginning of the lifecycle, i.e., when you loaded up the page, and then whenever the data is going to be changing, you just go run that typeset variable again and it just catches up and cleans up whatever it sees on the page and takes care of that for you. I find this to be pretty exciting. This allows you to lay out all sorts of really interesting scientific computing and, you know, research paper type applications, you know, through WeWeb. And you didn't really have to bring that much JavaScript to the party. You brought a little bit at the beginning, a little bit in the middle, then everything else gets to be the same usual, you know, collections and components, et cetera, through the control plane. And that is really where the power of low-code is. And that's the kind of thing, by the way, that we do pretty much, you know, every day over at StateChange is focusing on how we're going— what's that little bit of the application that's really special and different and how to bring in the thing that seems really hard and make it not so hard. Hopefully you'll be able to do this yourself with LaTeX and WeWeb, and it'll be not so hard for you, and we'll see you next time.










