Syntax Highlighter
Develop a client component for a syntax-highlighting code editor.
Environment
Use the environment you are most comfortable with. Because the React docs site suggests using a full-stack React framework, these challenges use the most popular of these frameworks, Next.js. You can run
npx create-next-app@latest
from your terminal to set up a new Next.js project, then use npm run dev
to develop locally and inspect the DOM from your browser when debugging. I opt to use App Router, made stable in Next.js 13.4
over the Pages Router. I also use tailwindcss for simple inline styling.
Specification
Develop a client component for a syntax-highlighting code editor. The primary goal is to create an intuitive interface allowing users to input code, select a programming language, and view the syntax-highlighted code in real-time.
The component should consist of two main sections: a textarea for code input and a preformatted block for displaying the highlighted code. Utilize the Prism library to achieve syntax highlighting, ensuring that the code is re-highlighted whenever the user modifies the input or changes the selected programming language. Implement a dropdown menu for language selection, offering options for HTML, JavaScript, and CSS.
Focus on a clean and simple design. The default language upon initialization should be JavaScript.
Here are a few images of the finished application:
Starter Code
Below is a small skeleton of the application to get you started.
app/page.tsx
import CodeReader from './CodeReader'
export default function Home() {
return (
<div className='flex justify-center h-screen w-screen pt-10'>
<CodeReader/>
</div>
)
}
app/CodeReader.tsx
'use client'
import Prism from 'prismjs';
import 'prismjs/themes/prism.css'
const LANGUAGES = ['html', 'javascript', 'css'];
export type Language = typeof LANGUAGES[number];
export default function CodeReader(){
// YOUR CODE HERE
}
Solution
Below is the entire solution code for the component followed by a short explanation of how it works.
app/CodeReader.tsx
'use client'
import { useEffect, useState } from "react"
import Prism from 'prismjs';
import 'prismjs/themes/prism.css'
const LANGUAGES = ['html', 'javascript', 'css'];
export type Language = typeof LANGUAGES[number];
export default function CodeReader(){
const [text, setText] = useState('')
const [language, setLang] = useState<Language>('javascript')
useEffect(() => {
Prism.highlightAll()
}, [text, language])
return (
<div className="w-2/4 h-3/4">
<div className="relative h-1/2">
<textarea className="w-full h-full" value={text} onChange={(e) => setText(e.target.value)}></textarea>
</div>
<div className="relative h-1/2">
<pre className={`h-full language-${language}`}>
<code className={`language-${language}`}>
{text}
</code>
</pre>
<select value={language} onChange={(e) => setLang(e.target.value)} className="absolute top-2 right-2">
{LANGUAGES.map((lang) => <option value={lang}>{lang}</option>)}
</select>
</div>
</div>
)
}
The component begins with import statements, bringing in necessary dependencies. useEffect
and useState
are imported from React for managing side effects and state, respectively. Prism
is imported for syntax highlighting, and the associated styles from 'prismjs/themes/prism.css' are included.
A constant array LANGUAGES
is defined, containing three string values: 'html', 'javascript', and 'css'. A TypeScript type Language
is created using typeof LANGUAGES[number]
, ensuring that the type can only be one of the values in the LANGUAGES
array.
The main CodeReader
component is defined as a functional component. Two state variables, text
and language
, are initialized using the useState
hook. The text
state holds the content of the code input, while the language
state represents the selected programming language for syntax highlighting (defaulted to 'javascript').
The useEffect
hook is used to trigger Prism's highlightAll
function whenever there are changes in the text
or language
state variables. This ensures that the code input is syntax-highlighted in real-time based on the selected programming language.
The code editor is divided into two sections using nested <div>
elements. The first section contains a textarea
for code input. The value of the textarea
is controlled by the text
state variable, and the onChange
event updates the text
state.
The second section contains a pre
element for displaying the syntax-highlighted code. The language
state is used to dynamically set the class for Prism highlighting. Additionally, a select
element is included to allow users to choose the programming language. The value
and onChange
attributes are used to manage the language
state.