DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for How I made a live code editor with Vanilla Javascript?
Muhammet Fatih Gul
Muhammet Fatih Gul

Posted on

How I made a live code editor with Vanilla Javascript?

I'm a huge fan of Codepen and Codesandbox websites. I tried to make a website like them some times. Ofcourse they're huge. I wasn't gonna be able to make a websites like them, but i wanted to see through how the things works. This is just a beginning. I'm going to make a website to render React JS and JSX codes live next.

CodeXC Editor

Libraries that I used

Codemirror already has CDNs to import but i wanted to import it locally. If you just want to try it out, you can use CDNs.

<!-- Codemirror Library -->
<script src="./Codemirror/lib/codemirror.js"></script>
<link rel="stylesheet" href="./Codemirror/lib/codemirror.css">
<link rel="stylesheet" href="./Codemirror/theme/ayu-mirage.css">
<!-- MODES TO HIGHLIGHT CODES -->
<script src="./Codemirror/mode/javascript/javascript.js"></script>
<script src="./Codemirror/mode/css/css.js"></script>
<script src="./Codemirror/mode/xml/xml.js"></script>
<!-- ADDONS -->
<script src="./Codemirror/addon/selection/active-line.js"></script>
<!-- Style -->
<link rel="stylesheet" href="style.css">
Enter fullscreen mode Exit fullscreen mode

Codemirror has so many addons like folding code blocks, autocomplete, custom searching input, auto closing brackets, auto closing tags etc.

And here is how my html look like:

<div class="container">
        <div class="pane code-pane">
            <div class="html-box code-box" id="html-box">
                <div class="title">
                    <span class="title-text">
                        HTML
                    </span>
                </div>
            </div>
            <div class="css-box code-box" id="css-box">
                <div class="title">
                    <span class="title-text">
                        CSS
                    </span>
                </div>
            </div>
            <div class="js-box code-box" id="js-box">
                <div class="title">
                    <span class="title-text">
                        JS
                    </span>
                </div>
            </div>
        </div>
        <div class="pane output">
            <iframe id="preview" frameborder="0"></iframe>
        </div>
    </div>
    <script src="app.js"></script>
Enter fullscreen mode Exit fullscreen mode

There's two section. Bottom and top. They has pane class for the common purposes and unique classes for the differences.

Top pane has html, css and js sections init and everyone has their own titles. That's it.

And here is my CSS codes look like:

body{box-sizing: border-box;margin: 0; padding: 0; font-family: monospace;}
.container{
    width: 100vw; height: 100vh; overflow: hidden; background-color: #ddd;
    display: flex; flex-direction: column; }
.pane{ width: 100%; height: 50%; }
.code-pane{ background-color: aqua; display: flex; }
.output{ background-color: aquamarine; }
.code-box{ width: 34%; height: 100%; display: flex;  flex-direction: column;
    box-sizing: border-box; border-right: 1px solid white; font-size: 1.3rem; }
.html-box{ background-color: azure; resize: horizontal; overflow: auto; }
.css-box{ background-color: bisque; resize: horizontal; overflow: auto; }
.js-box{ background-color: blanchedalmond; resize: horizontal; overflow: auto;}
.title{ width: 100%; height: 40px; background-color: cadetblue; }
.title-text{ color: white; font-size: 2rem; margin-left: 20px;
     padding: 0 10px 0 10px; background-color: #3d3d3d; }
.CodeMirror{ height: 100%;}
#preview { width: 100%; height: 100%; background-color: cadetblue; }
Enter fullscreen mode Exit fullscreen mode

HTML, CSS and JS boxes have resize functionalities horizontally. But i didn't use any other library to make it better. I only used CSS "resize: horizontal;" to make the divs resizable. But i'm sure it wouldn't be that much hard to make it. You can just use vanilla javascript and some math to do it.

And here is my javascript file:

//Code Mirror Initialization

var htmlCodeInstance = CodeMirror(document.getElementById("html-box"), {
    lineNumbers: true,
    tabSize: 4,
    mode: "xml",
    theme: "ayu-mirage",
    styleActiveLine: true,
});
var cssCodeInstance = CodeMirror(document.getElementById("css-box"), {
    lineNumbers: true,
    tabSize: 4,
    mode: "css",
    theme: "ayu-mirage",
    styleActiveLine: true,
});
var jsCodeInstance = CodeMirror(document.getElementById("js-box"), {
    lineNumbers: true,
    tabSize: 4,
    mode: "javascript",
    theme: "ayu-mirage",
    styleActiveLine: true,
});

// Run update() function, when the instances have change
htmlCodeInstance.on("change", function(){
    console.log(htmlCodeInstance.getValue())
    update();
});
cssCodeInstance.on("change", function(){
    console.log(cssCodeInstance.getValue())
    update();
});
jsCodeInstance.on("change", function(){
    console.log(jsCodeInstance.getValue())
    update();
});

//Change iFrame when you receive changes
function update() {
    let preview = document.getElementById("preview").contentWindow.document;
    codeTemplate = `
    <!DOCTYPE html>
    <html>
    <head>
    <style>`
     + cssCodeInstance.getValue() + 
    `</style>
    <body>` + 
    htmlCodeInstance.getValue() +
    `<script>` + jsCodeInstance.getValue() + `</script>` +
    `</body>
    </html>`
    console.log("CODE TEMPLATE: " + codeTemplate)
    preview.open();
    preview.write(codeTemplate);
    preview.close();
}
Enter fullscreen mode Exit fullscreen mode

In the first part. I initialized my divs to the Codemirror and give some properties. I know there's a better way to do it. Please check this out before you use this method.

In the second part, I gave it "onchange" method all of the editors that I have in the page. If one of them has changed update() function will be called.

".on()" method is built-in in Codemirror. So, I didn't use "addEventListener" or "onChange" property in HTML document. This is a better way I think.

and finally, in the last part, I take the iframe in the html document. This function only be called when the user type something in one of the editors.

I made a Code Template. So, when the user change something in one of the editors, they'll change the template and i'll write it to the iframe.

That's it. Hope you like it. See you soon.

SEE GITHUB REPOSITORY

Top comments (4)

Collapse
 
lukeshiru profile image
Luke Shiru

You might want to use Workers or something that runs your code in a different process safely, because if I'm reading your code correctly, if you write something like while (1){} in the JS editor, you freeze the entire app.

Collapse
 
hepisec profile image
hepisec

It shouldn't matter because the code is sent to the client and is not evalled. So the client would freeze itself if it enters while (1) {}

Collapse
 
lukeshiru profile image
Luke Shiru

.... it still matters. If you're writing while(value) { and said value starts as a truthy and you were planning to set it to falsy inside that while, you'll never be able to do that because the editor will freeze before that. You write infinite loops all the time, you just write the logic to stop them after, if an editor renders as soon as you write, it will freeze. It should ideally show an error as editors like CodeSandbox, CodePen or StackBlitz do.

Collapse
 
mfatihgul profile image
Muhammet Fatih Gul

I'll learn about it soon and improve myself. Thank you so much for your advice

Why You Need to Study Javascript Fundamentals

The harsh reality for JS Developers: If you don't study the fundamentals, you'll be just another β€œCoder”. Top learnings on how to get to the mid/senior level faster as a JavaScript developer by Dragos Nedelcu.