Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save dragontheory/5ad1465181a21e8ba63ddd58e7987832 to your computer and use it in GitHub Desktop.

Select an option

Save dragontheory/5ad1465181a21e8ba63ddd58e7987832 to your computer and use it in GitHub Desktop.

Creating a Repeatable Web Component for JSON Data Rendering

This guide explains how to create a single repeatable web component that dynamically handles multiple data points from a JSON file. The component will:

  • Populate <user-name></user-name> with a user's name.
  • Render search results inside <search-results> with dynamic rows based on available vertical space.
  • Populate <label> elements inside <nav> for accessible tab navigation.
  • Render paragraphs inside <section> elements.

The component will use modern CSS for layout and accessibility, minimizing JavaScript usage.


1. JSON Data Example

The following JSON structure will be used to populate our web component:

{
  "user": { "name": "John Doe" },
  "searchResults": [
    { "id": 1, "text": "First Result" },
    { "id": 2, "text": "Second Result" },
    { "id": 3, "text": "Third Result" }
  ],
  "tabs": [
    { "id": "tab1", "label": "Home", "content": "Welcome to Home" },
    { "id": "tab2", "label": "About", "content": "About Section" },
    { "id": "tab3", "label": "Contact", "content": "Contact Us" }
  ]
}

2. Web Component Definition

Create a reusable Web Component that processes this JSON data and populates the HTML structure.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Web Component Example</title>
  <script>
    class DynamicData extends HTMLElement {
      async connectedCallback() {
        const response = await fetch('data.json');
        const data = await response.json();

        if (this.tagName === 'USER-NAME') {
          this.innerText = data.user.name;
        }
        
        if (this.tagName === 'SEARCH-RESULTS') {
          this.innerHTML = `<div class="results-container">` + data.searchResults.map(
            item => `<p class="result">${item.text}</p>`
          ).join('') + `</div>`;
        }

        if (this.tagName === 'NAV') {
          this.innerHTML = data.tabs.map(
            tab => `
              <input type="radio" id="${tab.id}" name="tabs" hidden>
              <label for="${tab.id}">${tab.label}</label>
            `
          ).join('');
        }

        if (this.tagName === 'SECTION') {
          this.innerHTML = data.tabs.map(
            tab => `<p>${tab.content}</p>`
          ).join('');
        }
      }
    }
    
    customElements.define('user-name', DynamicData);
    customElements.define('search-results', DynamicData);
    customElements.define('nav', DynamicData);
    customElements.define('section', DynamicData);
  </script>
  <style>
    nav {
      display: flex;
      gap: 1rem;
    }
    label {
      cursor: pointer;
      padding: 0.5rem;
      background: #ddd;
    }
    input:checked + label {
      background: #aaa;
    }
    section p {
      display: none;
    }
    input:checked ~ section p {
      display: block;
    }
    search-results {
      display: block;
      max-height: 50vh;
      overflow: auto;
    }
    .results-container {
      display: grid;
      grid-template-rows: repeat(auto-fill, minmax(1rem, 1fr));
    }
  </style>
</head>
<body>
  <h1>Dynamic Web Component</h1>
  
  <p>Hello, <user-name></user-name>!</p>
  
  <h2>Search Results</h2>
  <search-results></search-results>
  
  <h2>Tabs</h2>
  <nav></nav>
  <section></section>
</body>
</html>

3. Explanation of Implementation

a. Fetching and Populating Data

  • The Web Component fetches data.json and determines the appropriate rendering logic based on its tag.

b. User Name (<user-name>)

  • Extracts data.user.name and inserts it inside the tag.

c. Search Results (<search-results>)

  • Iterates over data.searchResults to create paragraph elements dynamically.
  • Uses grid-template-rows: repeat(auto-fill, minmax(1rem, 1fr)); for responsive rendering based on available space.
  • Encapsulates search results in .results-container to provide structured styling and allow dynamic row allocation.

d. Navigation (<nav>) and Tabs (<section>)

  • Iterates over data.tabs to create radio button inputs with corresponding labels for accessible tab navigation.
  • Uses CSS selectors to control visibility based on which radio input is checked.

4. Summary

This solution:

  • Uses a single Web Component to manage different data needs.
  • Dynamically renders JSON data inside semantic elements.
  • Uses modern CSS techniques like auto-fill and :checked selectors for usability and responsiveness.
  • Keeps the HTML minimal while ensuring accessibility and a seamless user experience.

This method creates a scalable, maintainable component architecture that enhances both development efficiency and user experience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment