I'm trying to render errors created from the user's incorrect HTML code. According to the doc, this feature is available by default, but for some reason Monoco-React isn't catching the errors- it won't even log them. I'm using Monaco-React 1.1.0 and React 18.2.0. Below is my simplified code.
My component code:
// Basic file info for Monoco editor
const files = {
"index.html": {
name: "index.html",
language: 'html',
value: `<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
<button onclick="myFunction()">
Click
</button>
<p>What causes errors in HTML?
<!-- below are the errors from the "user" -->
<ul>
<li>Unclosed elements: If an element is <strong>not closed properly,
then its effect can spread to areas you didn't intend
<li>Badly nested elements: Nesting elements properly is also very important
for code behaving correctly. <strong>strong <em>strong emphasized?</strong>
what is this?</em>
<li>Unclosed attributes: Another common source of HTML problems. Let's
look at an example: <a href="https://www.mozilla.org/>link to Mozilla
homepage</a>
</ul>
<!-- above are the errors from the "user" -->
</body>
</html>`
}, 'style.css': {
name: 'style.css',
language: 'css',
value: `* {
padding: 0;
margin: 0;
border: 0;
font: inherit;
vertical-align: baseline;
}
h1{
display: block;
font-size: 2em;
font-weight: bold;
}
button{
margin: 10px;
padding: 10px;
cursor: pointer;
}`
}, 'script.js': {
name: 'script.js',
language: 'javascript',
value: `function myFunction(){
console.log("Hello World!");
}`,
}
}
const Sandbox = () => {
const [openedEditor, setOpenedEditor] = useState('html');
const [fileName, setFileName] = useState('index.html');
const editorRef = useRef(null);
const file = files[fileName];
const [html, setHtml] = useState(files['index.html'].value);
const [css, setCss] = useState(files['style.css'].value);
const [javascript, setJavascript] = useState(files['script.js'].value);
const [srcDoc, setSrcDoc] = useState(``);
const [htmlErrors, setHtmlErrors] = useState([]);
const [cssErrors, setCssErrors] = useState([]);
const [jsErrors, setJsErrors] = useState([]);
const [srcErrors, setSrcErrors] = useState([]);
const [copyMsg,setCopyMsg] = useState('');
const options = {
autoDetectHighContrast: true,
screenReaderAnnounceInlineSuggestion: true,
wordWrap: "on",
renderValidationDecorations: "on",
cursorWidth: 50,
renderValidationDecorations: true,
}
// Updates states depending on which tab is open
useEffect(() => {
openedEditor == "html" ? setFileName("index.html")
: openedEditor == "css" ? setFileName("style.css")
: setFileName('script.js');
}, [openedEditor, html, css, javascript]);
function handleEditorDidMount(editor, monaco) {
editorRef.current = editor;
}
// On validation, it sets the appropriate states with marker data
function handleEditorValidation(markers) {
// Model markers
const timeOut = setTimeout(() => {
setCssErrors([]);
for (const prop in markers) {
// responsible for updating validation states
if (openedEditor == "html") {
setHtmlErrors([...htmlErrors, {
line: markers[prop].startLineNumber,
lineEnd: markers[prop].endLineNumber,
col: markers[prop].startColumn,
msg: markers[prop].message
}])
} else if (openedEditor == "css") {
setCssErrors([...cssErrors, {
line: markers[prop].startLineNumber,
lineEnd: markers[prop].endLineNumber,
col: markers[prop].startColumn,
msg: markers[prop].message
}])
} else {
setJsErrors([...jsErrors, {
line: markers[prop].startLineNumber,
lineEnd: markers[prop].endLineNumber,
col: markers[prop].startColumn,
msg: markers[prop].message
}])
}
};
console.log(cssErrors);
}, 1000);
return () => clearTimeout(timeOut);
}
return (
<div className='sandbox'>
<div className="editor-container">
<div className='editor-wrapper'>
<Editor
className='main-editor'
theme='vs-dark'
options={options}
path={file.name}
onMount={handleEditorDidMount}
defaultLanguage={file.language}
defaultValue={file.value}
onValidate={handleEditorValidation} // This isn't activating for HTML code
onChange={() => {
const editorValue = editorRef.current.getValue();
openedEditor == "html" ? setHtml(editorValue)
: openedEditor == "css" ? setCss(editorValue)
: setJavascript(editorValue);
}}
wordWrap= {true}
/>
</div>
</div>
</div>
)
}
export default Sandbox;
The reason onValidate={handleEditorValidation} does not validate HTML in your code is that you are not using any HTML validation library or function in the handleEditorValidation function. The handleEditorValidation function in your code simply logs the markers array to the console.
To validate HTML, you can use a library like html-validator or a built-in browser API like DOMParser to parse and validate the HTML code. Here's an updated version of your code that uses the DOMParser to validate the HTML code:
https://feedic.com/htmlparser2/