OB电竞比赛结果

About The Author

Daniel Don is a software developer who loves sharing his knowledge and explaining seemingly difficult topics with relatable examples. He lives in Port Harcourt … More about Daniel ↬

Email Newsletter

Weekly tips on front-end & UX .
Trusted by 200,000+ folks.

If you’re a developer who’s thinking about building a platform that requires a code editor in one form or another, then this article is for you. This article explains how to create a web code editor that displays the result in real time with the help of some HTML, CSS and JavaScript.

An online web code editor is most useful when you do not have the opportunity to use a code editor application, or when you want to quickly try out something on the web with your computer or even your mobile phone. This is also an interesting project to work on because having the knowledge of how to build a code editor will give you ideas on how to approach other projects that require you to integrate a code editor to show some functionality.

Here are a few React concepts you’ll need to know in order to follow along in this article:

  • Hooks,
  • Component structure,
  • Functional components,
  • Props.

Using CodeMirror

We will be using a library named CodeMirror to build our editor. CodeMirror is a versatile text editor implemented in JavaScript for the browser. It is especially for editing code and comes with a number of language modes and add-ons for more advanced editing functionality.

A rich programming API and a CSS theming system are available for customizing CodeMirror to fit your application and extending it with new functionality. It gives us the functionality to create a rich code editor that runs on the web and shows us the result of our code in real time.

In the next section, we will set up our new React project and install the libraries we need to build our web app.

Creating A New React Project

Let’s start by creating a new React project. In your commandline interface, navigate to the directory in which you want to create your project, and let’s create a React application and name it code_editor :

									
									npx create-react-app code_editor
								
							

Having created our new React application, let’s navigate to that project’s directory in the commandline interface:

								
								cd code_editor
							
						

There are two libraries we need to install here: codemirror and react-codemirror2 .

					
					npm install codemirror react-codemirror2
				
			

Having installed the libraries we need for this project, let’s create our tabs and enable tab switching between the three tabs that will appear in our editor (for HTML, CSS, and JavaScript).

More after jump! Continue reading below ↓

Button Component

Instead of creating individual buttons, let’s make the button a component that is reusable. In our project, the button would have three instances, according to the three tabs we need.

Create a folder named components in the src folder. In this new components folder, create a JSX file named Button.jsx .

Here is all of the code needed in the Button component:

	
	import React from 'react' const Button = ({title, onClick}) => { return (
	
) } export default Button

Here is a full explanation of what we did above:

  • We created a functional component named Button , which we then exported.
  • We destructured title and onClick from the props coming into the component. Here, title would be a string of text, and onClick would be a function that gets called when a button is clicked.
  • Next, we used the button element to declare our button, and used the style attributes to style our button to look presentable.
  • We added the onClick attribute and passed our destructured onClick function props to it.
  • The last thing you’ll notice we did in this component is pass in {title} as the content of the button tag. This allows us to display the title dynamically, based on what prop is being passed to the instance of the button component when it is called.

Now that we have created a reusable button component, let’s move on and bring our component into App.js. Go to App.js and import the newly created button component:

	
	import Button from './components/Button';

To track which tab or editor is open, we need a declare state to hold the value of the editor that is open. Using the useState React hook, we’ll set up the state that will store the name of the editor tab that is currently open when that tab’s button is clicked.

Here is how we do that:

	
	import React, { useState } from 'react'; import './App.css'; import Button from './components/Button'; function App() { const [openedEditor, setOpenedEditor] = useState('html'); return (
	
); } export default App;

Here, we declared our state. It takes the name of the editor that is currently open. Because the value html is passed as the state’s default value, the HTML editor would be the tab open by default.

Let’s move on and write the function that will use setOpenedEditor to change the value of the state when a tab button is clicked.

Note: Two tabs may not be open at the same time, so we’ll have to consider that when writing our function.

Here is what our function, named onTabClick , looks like:

	
	import React, { useState } from 'react'; import './App.css'; import Button from './components/Button'; function App() { ... const onTabClick = (editorName) => { setOpenedEditor(editorName); }; return (
	
); } export default App;

Here, we passed a single function argument, which is the name of the tab currently selected. This argument would be supplied anywhere the function is called, and the relevant name of that tab would be passed in.

Let’s create three instances of our Button for the three tabs we need:

	
	

Welcome to the editor!

Here is what we did:

  • We started by adding a p tag, basically just to give some context to what our application is about.
  • We used a div tag to wrap our tab buttons. The div tag carries a className that we will use to style the buttons into a grid display in the CSS file later in this tutorial.
  • Next, we declared three instances of the Button component. If you recall, the Button component takes two props, title and onClick . In every instance of the Button component, these two props are provided.
  • The title prop takes the title of the tab.
  • The onClick prop takes a function, onTabClick , which we just created and which takes a single argument: the name of the tab selected.

Based on the tab currently selected, we would use the JavaScript ternary operator to display the tab conditionally. This means that if the value of the openedEditor state is set to html (i.e. setOpenedEditor('html') ), then the tab for the HTML section would become the currently visible tab. You’ll understand this better as we do it below:

	
	... return (
	
...
{ openedEditor === 'html' ? (

The html editor is open

) : openedEditor === 'css' ? (

The CSS editor is open!!!!!!

) : (

the JavaScript editor is open

) }
); ...

Let’s go over the code above in plain English. If the value of openedEditor is html , then display the HTML section. Otherwise, if the value of openedEditor is css , then display the CSS section. Otherwise, if the value is neither html nor css , then that means the value must be js , because we have only three possible values for the openedEditor state; so, then we’d display the tab for JavaScript.

We used paragraph tags ( p ) for the different sections in the ternary operator conditions. As we proceed, we will create the editor components and replace the p tags with the editor components themselves.

We have come so far already! When a button is clicked, it fires up the action that sets the tab it represents to true , making that tab visible. Here’s what our app currently looks like:

A GIF showing the tab toggle we currently have.
A GIF showing the tab toggle we currently have. ( Large preview )

Let’s add a little CSS to the div container holding the buttons. We want the buttons to be displayed in a grid, instead of stacked vertically like in the image above. Go to your App.css file and add the following code:

	
	.tab-button-container{ display: flex; }

Recall that we added className="tab-button-container" as an attribute in the div tag holding the three-tab buttons. Here, we styled that container, using CSS to set its display to flex . This is the result:

We use CSS to set its display to flex
( Large preview )

Be proud of how much you’ve done to get to this point. In the next section, we will create our editors, replacing the p tags with them.

Creating the Editors

Because we have already installed the libraries we are going to be working on within our CodeMirror editor, let’s go ahead and create our Editor.jsx file in the components folder.

components > Editor.jsx

Having created our new file, let’s write some initial code in it:

		
		import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { return (
		
) } export default Editor

Here’s what we did:

  • We imported React alongside the useState hook because we are going to need it.
  • We imported the CodeMirror CSS file (which comes from the CodeMirror library that we installed, so you don’t have to install it in any special way).
  • We imported Controlled from react-codemirror2 , renaming it to ControlledEditorComponent to make it clearer. We will be using this shortly.
  • Then, we declared our Editor functional component, and we have a return statement with an empty div , with a className in the return statement for now.

In our functional component, we destructured some values from the props, including language , value , and setEditorState . These three props would be supplied in any instance of the editor when it is called in App.js .

Let’s use ControlledEditorComponent to write the code for our editor. Here’s what we’ll do:

		
		import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/css/css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { return (
		
) } export default Editor

Let’s walk through what we did here, explaining some CodeMirror terms.

The CodeMirror modes specify which language an editor is meant for. We imported three modes because we have three editors for this project:

  1. XML: This mode is for HTML. It uses the term XML.
  2. JavaScript: This ( codemirror/mode/javascript/javascript ) brings in JavaScript mode.
  3. CSS: This ( codemirror/mode/css/css ) brings in CSS mode.

Note: Because the editor is built as a component that is reusable, we cannot put a direct mode in the editor. So, we supply the mode through the language prop that we destructured. But this doesn’t change the fact that the modes need to be imported in order to work.

Next, let’s discuss the things in ControlledEditorComponent :

  • onBeforeChange
    This is called anytime you write to or remove from the editor. Think of this like the onChange handler you would normally have in an input field to track changes. Using this, we will be able to get the value of our editor anytime there’s a new change and save it to our editor’s state. We will write the {handleChange} function as we proceed.
  • value = {value}
    This is just the content of the editor at any given time. We passed a destructured prop named value to this attribute. The value props is the state holding the value of that editor. This would be supplied from the editor’s instance.
  • className ="code-mirror-wrapper"
    This class name is not a style we make ourselves. It is supplied from CodeMirror’s CSS file, which we imported above.
  • options
    This is an object that takes the different functionality we want our editor to have. There are many amazing options in CodeMirror. Let’s look at the ones we used here:
    • lineWrapping: true
      This means that code should wrap to the next line when the line is full.
    • lint: true
      This allows linting.
    • mode: language
      This mode, as discussed above, takes the language that the editor is going to be used for. The language has already been imported above, but the editor is going to apply a language based on the language value supplied to the editor via the prop.
    • lineNumbers: true
      This specifies that the editor should have line numbers for each line.

Next, we can write the handleChange function for the onBeforeChange handler:

	
	const handleChange = (editor, data, value) => { setEditorState(value); }

The onBeforeChange handler gives us access to three things: editor, data, value .

We only need the value because it is what we want to pass in our setEditorState prop. The setEditorState prop represents the set value for each state that we declared in App.js , holding the value for each editor. As we move on, we will look at how to pass this as a prop to the Editor component.

Next, we’ll add a dropdown that allows us to select different themes for the editor. So, let’s look at themes in CodeMirror.

CodeMirror Themes

CodeMirror has multiple themes we can select from. Visit the official website to see demos of the different themes available. Let’s make a dropdown with different themes that the user can choose from in our editor. For this tutorial, we’ll be adding five themes, but you can add as many as you like.

First, let’s import our themes in the Editor.js component:

	
	import 'codemirror/theme/dracula.css'; import 'codemirror/theme/material.css'; import 'codemirror/theme/mdn-like.css'; import 'codemirror/theme/the-matrix.css'; import 'codemirror/theme/night.css';

Next, create an array of all of the themes we have imported:

		
		const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night']
	

Let’s declare a useState hook to hold the value of the selected theme, and set the default theme as dracula :

	
	const [theme, setTheme] = useState("dracula")

Let’s create the dropdown:

	
	... return (
	
// the rest of the code comes below...
) ...

In the code above, we used the label HTML tag to add a label to our dropdown, and then added the select HTML tag to create our dropdown. The option tag in the select element defines the options available in the dropdown.

Because we needed to fill the dropdown with the theme names in the themeArray that we created, we used the .map array method to map themeArray and display the names individually using the option tag.

Hold on — we’re not done explaining the code above. In the opening select tag, we passed the onChange attribute to track and update the theme state whenever a new value is selected in the dropdown. Whenever a new option is selected in the dropdown, the value is gotten from the object returned to us. Next, we use the setTheme from our state hook to set the new value to be the value that the state holds.

At this point, we have created our dropdown, set up our theme’s state, and written our function to set the state with the new value. The final thing we need to do to make CodeMirror use our theme is pass the theme to the options object in ControlledEditorComponent . In the options object, let’s add a value named theme , and set its value to the state’s value for the selected theme, also named theme .

Here’s what ControlledEditorComponent would look like now:

	
	

Now, we have made a dropdown of different themes that can be selected from in the editor.

Here’s what the full code in Editor.js looks like at the moment:

		
		import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import 'codemirror/theme/dracula.css'; import 'codemirror/theme/material.css'; import 'codemirror/theme/mdn-like.css'; import 'codemirror/theme/the-matrix.css'; import 'codemirror/theme/night.css'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/css/css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { const [theme, setTheme] = useState("dracula") const handleChange = (editor, data, value) => { setEditorState(value); } const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night'] return (
		
) } export default Editor

There’s only one className that we need to style. Go to App.css and add the following style:

	
	.editor-container{ padding-top: 0.4%; }

Now that our editors are ready, let’s go back to App.js and use them there.

src > App.js

The first thing we need to do is import the Editor.js component in here:

	
	import Editor from './components/Editor';

In App.js , let’s declare the states that will hold the contents of the HTML, CSS, and JavaScript editors, respectively.

	
	const [html, setHtml] = useState(''); const [css, setCss] = useState(''); const [js, setJs] = useState('');

If you recall, we will need to use these states to hold and supply the contents of our editors.

Next, let’s replace the paragraph ( p ) tags that we used for the HTML, CSS, and JavaScript in the conditional renderings with the editor components we have just created, and we’ll also pass in the appropriate prop to each instance of the editor component:

	
	function App() { ... return (
	

Welcome to the edior

// This is where the tab buttons container is...
{ htmlEditorIsOpen ? ( ) : cssEditorIsOpen ? ( ) : ( ) }
); } export default App;

If you’ve been following along until now, you’ll understand what we did in the code block above.

Here it is in plain English: We replaced the p tags (which were there as placeholders) with instances of the editor components. Then, we supplied their language , value , and setEditorState props, respectively, to match their corresponding states.

We’ve come so far! Here is what our app looks like now:

The way our app looks like now
( Large preview )

Introduction to Iframes

We’ll be making use of inline frames (iframes) to display the result of the code entered in the editor.

According to MDN :

The HTML Inline Frame element (

Smashing Editorial (ks, vf, yk, il, al)