Next.js Discord

Discord Forum

Ways to validate html

Answered
Mini Satin posted this in #help-forum
Open in Discord
Avatar
Mini SatinOP
Hello there, i'm working with [NextJS](https://nextjs.org/), [MDX editor](https://mdxeditor.dev/) and [next-mdx-remote](https://github.com/hashicorp/next-mdx-remote) and i need to ensure that my user input will produce valid HTML.
Is there a way i can spot some errors (like a div tag inside a p tag) before passing to MDXRemote component to prevent hydration errors ?

This can happen when i provide this input :
Hello world <Test/>

Assuming Test component is this :
const Test = () => <div>My Test component</div>

This will create this output :
<p>Hello world <div>My Test component</div></p>

Then i'll have those errors :
In HTML, <div> cannot be a descendant of <p>.
This will cause a hydration error.

Uncaught Error: Hydration failed because the server rendered HTML didn't match the client.
Answered by Mini Satin
Found another way to do it, as i got a preview, i'm sending it's innerHTML to this :
"use server";

import { HtmlValidate } from "html-validate";

export const validateHtmlTest = async (markup: string) => {
  const validator = new HtmlValidate();
  const report = await validator.validateString(markup);
  console.log("report", report);
};

Working like a charm, and it catches all other potential errors as well ❤️
View full answer

19 Replies

Avatar
@B33fb0n3 when you using mdx with custom component and user input, you should close everything after you opened it. Example: Hello World Produce: <p>Hello World</p> // <--- here everything is closed When adding a component now to it the p tag should be closed first: Hello World <Test /> Produce: <p>Hello world </p> // <--- close first <div>My Test component</div> So instead of nesting them into another (what you doing rn) you should close everything first to prevent issues
Avatar
Mini SatinOP
Yes i agree with that. The fact is that i do not control what the user provide. Neither how next-mdx-remote will process the input.
Hello world <Test/>

If this input is provided to the MDXRemote component, the result will be nested and i cannot detect it properly rn -> that's the issue.
What i would want to do is to prevent user to save the document if this kind of errors happens.
Avatar
@B33fb0n3 how do you want to detect if there are errors?
Avatar
Mini SatinOP
That's the all point. I tried to check if window.onerror would trigger but that's not the case 😦
I guess the best way would be to pre-render the html and pass it to a validator like [this one](https://www.npmjs.com/package/html-validate)
Avatar
Mini SatinOP
It would be possible with pure markdown and a package like marked but with mdx i cannot find a package that will do MDX to HTML without producing a component. And NextJS does not let me import from react-dom/server
Avatar
@Mini Satin why don't you create a html parser and parse the "new" html and check if there are any errors?

You can create a parser like this:
const doc = new DOMParser().parseFromString(html, "text/html");
Avatar
@B33fb0n3 <@180843812204183552> why don't you create a html parser and parse the "new" html and check if there are any errors? You can create a parser like this: tsx const doc = new DOMParser().parseFromString(html, "text/html");
Avatar
Mini SatinOP
Because i cannot retrieve my html into a string form, pure markdown is given to the MDXRemote component like this :
<MDXRemote source={"Hello world <Test/>"} components={{ Test }} />

I would need a way to first parse the mdx to have an HTML string then i would be able to do what you say
Avatar
@Mini Satin Because i cannot retrieve my html into a string form, pure markdown is given to the `MDXRemote` component like this : ts <MDXRemote source={"Hello world <Test/>"} components={{ Test }} /> I would need a way to first parse the mdx to have an HTML string then i would be able to do what you say
Avatar
when you are using the remote option of MDX you will retrieve the source first. This "source" will be also saved somewhere and somewhen. During this time, you can do the same: read it, check for Component (for example with regex) and check against that
Avatar
@Mini Satin What do you mean by "remote option" ?
Avatar
you can either use MDX as remote, so you load text from somewhere and pass it into it (see attached). Or you can configure nextjs so it creates automatically pages for MDX files
Image
Avatar
@B33fb0n3 you can either use MDX as remote, so you load text from somewhere and pass it into it (see attached). Or you can configure nextjs so it creates automatically pages for MDX files
Avatar
Mini SatinOP
Hum yeah ok.
My user does not have a direct access to the repository so i cannot use the build in feature of NextJS with page.mdx files.
That's why i'm using MDXRemote only.

The rendering code is that :
const Test = () => <div>My Test component</div>;

export default async function MyPage() {
  const markdown = await fetchMarkdownFromDb();
  return <MDXRemote source={markdown} components={{ Test }} />; // Transform the Markdown into a React component
}

I would like to validate the input when i save, here is my server action to save :
"use server";
import { compile } from "@mdx-js/mdx";
import { transformToHtml } from "some_html_transformer";
import { saveToDatabase } from "../myDatabaseStuff";

export const saveMarkdownServerAction = async (markdown: string) => {
  // working code to detect markdown syntax error :
  try {
    await compile(markdown);
  } catch (e) {
    return `Compilation failed ! {e.message}`;
  }
  
  // When i come at this point i know that the markdown syntax is okay
  // Here what i would need to prevent HTML errors, or something equivalent :
  try {
    await transformToHtml(markdown);
  } catch (e) {
    return `HTML transformation failed ! {e.message}`;
  }

  await saveToDb(markdown);
  return null;
};
Avatar
Mini SatinOP
Avatar
@B33fb0n3 Yea, why not doing this: https://discord.com/channels/752553802359505017/1313543272618000439/1313558507080912957
Avatar
Mini SatinOP
I could prevent some component to be used on the same line as regular markdown by parsing the mdx source but that would mean i could not have inline components and/or can lead to have heavy logic.
Maybe i'm not understanding well what you said here though...
Let's say i've got another component that produce <strong>Some text</strong> then this one is valid when used in a p tag whereas the other with the div is not valid.
Imo if i can parse directly the output html this would be less error prone and more effective.
Avatar
@B33fb0n3 Correct, if you need to you can build your own parser that allows specific components inline and others not
Avatar
Mini SatinOP
Ok i'm gonna check my customer and see what we'll do about this.
Thanks for your time and help ❤️
Avatar
@B33fb0n3 Correct, if you need to you can build your own parser that allows specific components inline and others not
Avatar
Mini SatinOP
Found another way to do it, as i got a preview, i'm sending it's innerHTML to this :
"use server";

import { HtmlValidate } from "html-validate";

export const validateHtmlTest = async (markup: string) => {
  const validator = new HtmlValidate();
  const report = await validator.validateString(markup);
  console.log("report", report);
};

Working like a charm, and it catches all other potential errors as well ❤️
Answer