Rendering JSON as HTML (and actually marking it up)

Hey team!

Here’s the TLDR of my post: I have a JSON object coming in via Xano, I need to render it as a paragraph, and have the elements inside of it be a mixture of text and links / buttons that can trigger workflows.

Ok, now that I’ve hooked you in, a little more explanation :smile:

I have a JSON object structured like this:

{
  "paragraphs": [
    {
      "segments": [
        {
          "text": "The collection of narrative assessments from meetings between a probation officer and a probationer over a period reflects a predominance of challenges and negative setbacks, with a consistent theme of non-compliance with testing requirements and missed appointments. The narratives frequently mention missed tests and appointments, suggesting a pattern of non-compliance and difficulties in adhering to the probation terms ",
          "citations": [
            {
              "contact_date": "2018-06-29",
              "narrative_idx": 48
            },
            {
              "contact_date": "2018-06-29",
              "narrative_idx": 47
            },
            {
              "contact_date": "2018-06-26",
              "narrative_idx": 46
            }
          ]
        },
        {
          "text": ". Additionally, there are instances of positive drug test results for various substances, indicating ongoing substance use, which further contributes to the negative outlook of these assessments ",
          "citations": [
            {
              "contact_date": "2018-04-26",
              "narrative_idx": 26
            },
            {
              "contact_date": "2018-03-30",
              "narrative_idx": 20
            }
          ]
        },
        {
          "text": ". While there are occasional mentions of positive progress, such as attending appointments on time, enrolling in treatment, and engaging in educational classes, these are overshadowed by the frequency and severity of the negative indicators ",
          "citations": [
            {
              "contact_date": "2018-06-08",
              "narrative_idx": 42
            },
            {
              "contact_date": "2018-04-10",
              "narrative_idx": 22
            }
          ]
        }
      ]
    },
    {
      "segments": [
        {
          "text": "Key intermediate outcomes mentioned across the narratives include some instances of the probationer attending appointments on time, enrolling in treatment programs, and engaging in educational classes. However, these positive steps are frequently counterbalanced by significant challenges, including financial struggles, missed tests, and positive drug test results for various substances ",
          "citations": [
            {
              "contact_date": "2018-06-08",
              "narrative_idx": 42
            },
            {
              "contact_date": "2018-04-10",
              "narrative_idx": 22
            },
            {
              "contact_date": "2018-03-30",
              "narrative_idx": 20
            }
          ]
        },
        {
          "text": ". The narratives also highlight a few instances where the probationer demonstrated compliance with alcohol-related probation terms, as indicated by negative drug test results for alcohol ",
          "citations": [
            {
              "contact_date": "2018-02-12",
              "narrative_idx": 7
            }
          ]
        },
        {
          "text": ". Despite these glimpses of progress, the overall sentiment of the case leans heavily towards negative outcomes, with a clear need for enhanced support and interventions to address the probationer's non-compliance and substance use issues.",
          "citations": []
        }
      ]
    }
  ]
}

Here’s a quick explanation:

  • There’s a parent wrapper called paragraph.
  • Within that are 2 segment wrappers, these are meant to be individual paragraphs.
  • Within that is a mixture of text and contact_dates and narrative_idx, which are meant to be citations for the text that proceeds them.
  • As you can see from the object, each paragraph has multiple text & citation contact_dates / narrative_idx pairs.

Ultimately I’m trying to render this entire object so these citations are inline links with their text, like this mockup:

Here’s the rub: These citations need to be links that trigger interactivity, such as opening up a dialog box that contains an accordion of all the citations, or really any interactivity I’d like to create a beautiful user experience.

Because I have the JSON marked up with such clear segmentation, my first approach was to render it as HTML with JS and have it add in links to anchor to an accordion on the page (before doing the dialog box). I did that with this JS and tagged the accordion with attributes to target them with the contact_date:

// Get the segments array from the data

const segments = context.item.data.segments;

// Initialize result string

let result = '';

// Process each segment

segments.forEach(segment => {

// Add the main text

result += segment.text;

// If there are citations, wrap them in parentheses

if (segment.citations && segment.citations.length > 0) {

result += '(';

// Build each citation

segment.citations.forEach((citation, index) => {

// Create a link that will find and click the matching accordion element

// Added style attributes for link appearance

result += `<a href="#" style="color: #0075df; text-decoration: underline;" onclick="event.preventDefault(); document.querySelector('[data-contact-date=\\'${citation.contact_date}\\']')?.scrollIntoView({behavior: 'smooth'}); setTimeout(() => document.querySelector('[data-contact-date=\\'${citation.contact_date}\\']')?.click(), 500);">${citation.contact_date}</a> [${citation.narrative_idx}]`;

// Add a comma if this isn't the last citation

if (index < segment.citations.length - 1) {

result += ', ';

}

});

result += ')';

}

});

// Return the final string with HTML links

return result;

I’ll put a video in the comments that shows how this works + how it’s rendering in the DOM, the form here isn’t allowing me to put in multiple links :slight_smile:

Okie dokie, knowing ALL of that, here are my questions:

  1. After getting this far, I’m unable to get any further with the dialog box. For example, instead of having these act as anchor links that drop you down the page, instead I’d like them to trigger a workflow that opens up a dialog box (that contains the same citations), and scroll to the respective citation. I have tried multiple JS onclick functions to no avail. I tend to get results that just reload the page or throw a series of console errors. Is there a way I can accomplish this with my current setup?

  2. I also tried to render this object in a series of nested lists, containing the text and citations separately so I could render the citations as actual button elements so I could trigger workflows with them, but I was never able to get them to render truly inline because of the separate containers. Is something like this a dead end, since these containers will never be able to be configured in a way that looks like a continuous paragraph?

  3. From the highest level, is there a better approach for taking in a nested JSON file like I have and parsing it into multiple element types (text, buttons, ect…) so I’m able to retain the control that my JSON gives me by marking up each element, but also maintain a high level of control on how they render via HTML so I can use native WeWeb workflows? Or is these just some other approach I’m unaware of? If I was just marking this up with raw HTML it feels like it wouldn’t be that hard, but I’m just not sure how WeWeb wants me to handle it.

Finally, I’m trying to build this in a way that is truly dynamic and reusable, knowing that the number of text / citations could differ greatly, given the use case.

I know this is a beast of a post, any help is HUGELY appreciated!!!

Here’s a link to a video showing how my current paragraph works with inline links since I couldn’t put it in the post above: CaseNectar | WeWeb - 26 March 2025 | Loom

Here’s also a crude mockup to show you how question #2 looks:

@Slavo / @Broberto - Wanted to tag you two here in case you had any insights :slight_smile:

Hey. I’d probably do this on the server, you’ll need a robust JavaScript function (for example a Xano’s Lambda) that will compose the markup that needs to be displayed. This seems like a big feature, so I can’t tell you much without seeing it myself. If you want, I offer 1:1 Consulting (https://broberto.sk/consult) where we might go over this in depth and put together a plan for you to execute.

@Broberto - Really appreciate it! I just booked with you for tomorrow :slight_smile: