Structured Text customization for list

Hi,

I was wondering if it’s possible to extend the Structured Text to allow a different type of bulleted list.

I want to have a <ul> with custom icon.

There are ways of doing this via customBlockStylesForStructuredTextField or customMarksForStructuredTextField but I’d like to apply this styling to the whole ul instead of the p tag inside the ul.

Thanks!

Hi @e.aisyah, and welcome to the forum!

Unfortunately, I don’t think you can do that inside the Dato UI (without using a field extension to manually override and re-implement the entire structured text editor, which would be really difficult).

But the Dato UI is something only your editors see. On your actual website frontend (what your visitors see), you can use CSS to override the list display with a custom icon… does that help at all? If you implement that, then you can use the web preview plugin to show your editors in Dato what the rendered list would actually like on the real website.

As an alternative, you can also make a block with a Markdown or HTML field, embed that block inside the Structured Text field, and render it differently (both on the frontend, based on its block model name, and also in the UI with a field extension… it’s much easier to render a Markdown or HTML field of bullets rather than the structured text format.)

Hi @roger,

Thank you for your response!

Using CSS to override can certainly help. However, how do I know which list on the sturctured text should be a custom icon and which one shouldn’t? Because the content creator will be the one who decide which list uses a custom icon and which icon should it use.

For that, I think you can use an embedded block:

The block has a simple schema, just a Markdown or HTML field (for the list items) and a separate single-line string one (for the bullet icon you want to use, configured as radio buttons in the presentation settings):

The query and API output would look like this:

Then on the frontend, you’d look for any blocks.listItems[] and render them with a different CSS class based on their customIcon property. You can also use our React component to do custom block rendering, if you prefer: https://github.com/datocms/react-datocms/blob/master/docs/structured-text.md#custom-renderers-for-inline-records-blocks-and-links

Does that help? Let me know if you need a full end-to-end example :slight_smile:

Hi Roger,

Thank you so much for the comprehensive reply. I will definitely use this solution and report back :slightly_smiling_face:

Hi Roger,

I managed to get to this point

        renderBlock={({ record }) => {
          switch (record.__typename) {
            case constants.DatocmsTypeNames.CUSTOM_LIST_BLOCK_RECORD:
              const customList = record as CustomListRecord;
              const htmlString = customList.listItems ?? "";
              const listItems = htmlString
                .match(/<li>(.*?)<\/li>/g)
                ?.map((item) => item.replace(/<\/?li>/g, ""));

              return (
                <ul className="list-none pl-0">
                  {listItems?.map((item, index) => (
                    <li key={index}>
                      <SearchCheckItem>{item}</SearchCheckItem>
                    </li>
                  ))}
                </ul>
              );

            default:
              return null;
          }
        }}

To render the custom list. However, is there a better way to get the <li> element that isn’t relying on regex?

Thank you!

Hmm, first of all, can I ask why you need to rewrite the individual <li>s? If you’re just trying to change the bullet style, you should be able to add a className (and the corresponding list-style CSS) to the wrapping <ul> to format all of them at once without having to edit the individual list items.

But to answer your question…

Probably, but it depends on your stack. What is your frontend using? Some examples:

  • The most “semantic” and straightforward way to do this might be make the block contain a Modular Content Field, Multiple Blocks, and have that wrap individual repeating “Custom List Item” single-string fields. That way you just get back a nested array of fields inside the JSON that you can then render however you please.
  • You can parse that HTML back into a syntax tree using https://github.com/syntax-tree/hast-util-from-html
  • Or if you don’t want to render the HTML directly, leave out the markdown: true parameter in the GraphQL and you’ll get back raw Markdown instead (which is easier to parse). You can parse it then with https://github.com/syntax-tree/mdast-util-from-markdown.
  • For the above (HTML and Markdown parsing) there are a bunch of other libs that work similarly; I just suggested the *AST (Abstract Syntax Tree) utilities because that’s what Structured Text is based on. For example, it might be easier (depending on your use case) to use:

While any of the above methods should work, if I better understood your overall use case and frontend stack, I might be able to recommend something more specific. Is there more complexity there than just custom bullet icons?

Yeah now it’s clear to me that I can just manipulate the <ul>. Sorry for the confusion.

Thank you for your answer!

1 Like

Great, glad that helped!