is their a max number of modals that can be used on a page or site? I have many cards on a page min 23 max 45 per page and does it make any difference in size of modal and test amount?
Thanks
is their a max number of modals that can be used on a page or site? I have many cards on a page min 23 max 45 per page and does it make any difference in size of modal and test amount?
Thanks
Why use a separate modal for your cards? Why not load the same modal with dynamic content inside?
Hello Teodor
I am doing this as a static site. And each item has a modal for the main specs for the item. If I can do dynamic for this i am all ears.
Is there a reason why you don't want to use a dynamic data source / database for this?
If you are not using database you can still put the list of assets in a json file and use that as dynamic source. See the included with Wappler demo site of dynamic real estate.
If you want to display the details of an item listed on a card, you can use a single modal like this:
<div class="modal fade" id="cardModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalTitle"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="modalBody"></div>
</div>
</div>
</div>
For the cards, you can add data attributes:
<div class="card" data-title="Card 1" data-content="Details for Card 1" onclick="openModal(this)">
<div class="card-body">Card 1</div>
</div>
<div class="card" data-title="Card 2" data-content="Details for Card 2" onclick="openModal(this)">
<div class="card-body">Card 2</div>
</div>
Finally, use a bit of JavaScript to make it work:
<script>
function openModal(card) {
document.getElementById('modalTitle').textContent = card.dataset.title;
document.getElementById('modalBody').textContent = card.dataset.content;
new bootstrap.Modal(document.getElementById('cardModal')).show();
}
</script>
This is similar to the method I used when creating the YouTubePlayer extension for Wappler.
Edit: In fact, this would make a great extension or even a custom element
<card-with-modal>HTML Usage
<card-with-modal title="Card 1" content="Details for Card 1"></card-with-modal>
<card-with-modal title="Card 2" content="Details for Card 2"></card-with-modal>
<!-- Repeat as needed -->
JavaScript Definition:
<script>
class CardWithModal extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
const title = this.getAttribute('title') || 'Untitled';
const content = this.getAttribute('content') || 'No content provided';
this.shadowRoot.innerHTML = `
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<div class="card m-2" style="cursor:pointer;">
<div class="card-body">
<h5 class="card-title">${title}</h5>
<button class="btn btn-primary" id="openBtn">Open</button>
</div>
</div>
<div class="modal fade" id="modal-${title.replace(/\s+/g, '-')}" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${title}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">${content}</div>
</div>
</div>
</div>
`;
const modalId = `modal-${title.replace(/\s+/g, '-')}`;
const openBtn = this.shadowRoot.getElementById('openBtn');
openBtn.addEventListener('click', () => {
const modal = new bootstrap.Modal(this.shadowRoot.getElementById(modalId));
modal.show();
});
}
}
customElements.define('card-with-modal', CardWithModal);
</script>
Notes for Integration
Hi Ben,
I think it's much easier to use JSON data source, instead of hand coding with custom js ![]()
this is the type of data that I need, the table and on the right side the large description. How do I format a json file for this? The page format does not do well for repeat row unless I do repeat row twice.
I don’t disagree at all; JSON is a powerful and flexible format. But have you ever gone through the process of manually crafting a deeply nested JSON file like this one?
[
{
"id": "TS50-640",
"name": "AGM Global Vision Varmint LRF TS50-640",
"specs": {
"Magnification": "2.5x",
"Objective Lens Diameter": "50 mm",
"Field of View": "8.78 x 7.03 Degrees",
"Dimensions": "8.85\" x 2.52\" x 2.31\"",
"Eye Relief": "45 mm",
"Exit Pupil Diameter": "6 mm",
"Shockproof / Waterproof": true,
"Detection Range": "2600 meters",
"Palettes": ["White Hot", "Black Hot", "Red Hot", "Fusion"],
"Battery Type": "18650 (3.7V) Lithium Rechargeable",
"Battery Life": "Up to 4.5 hours",
"Display Resolution": "0.39\" 1024x768 OLED",
"Thermal Sensor Type": "Thermal"
},
"status": "Out of Stock",
"description": "The Varmint LRF series is a popular thermal scope featuring a 600-meter integrated laser rangefinder. Designed for precision and durability.",
"actions": ["Add to Wishlist", "Add to Cart"]
}
// add more
]
It’s not just tedious, it’s error-prone and hard to maintain, especially for static sites.
That’s why I leaned toward using a custom element or even an extension. With that approach, you only input the values, and the structure handles itself. It’s cleaner, easier to maintain, and gives developers full control over layout without relying on repeat regions.
As a side note: Yes, one can create a form and have the server create the JSON file.
All roads lead to Rome
If it really has to be static,i would still drop on an Sqlite database (table with subtable) then the json could be generated by a query at design time and the output could then saved and be used as a json data source.
No they are all different and sometimes there are fewer items, but I can leave the ones blank that are not used.
There is not a limit to the number of modals on the page, so it is not a problem to have them static. The biggest problem is probably that your html will get very big and takes longer to download which makes your site slower for users with a slow connection. Making your html dynamic can make it smaller and faster.
Then i'd go with a structure like this, when specs can vary:
{
"products": [
{
"id": 1,
"brand": "AGM Global Vision",
"category": "Thermal Scopes",
"series": "TS50-640",
"model": "Varmint V2 LRF",
"status": "Out of Stock",
"mapp": 1234,
"msrp": 5678,
"qty": 4,
"image": "/img/products/agm-varmint-v2-lrf-ts50-640.jpg",
"shelf_tag": "/docs/agm-varmint-v2-lrf-ts50-640-shelftag.pdf",
"spec_sheet": "/docs/agm-varmint-v2-lrf-ts50-640-specs.pdf",
"description": "The Varmint LRF series adds a 600 m integrated laser rangefinder to the proven Rattler platform.",
"specs": [
{
"key": "Magnification",
"value": "2.5x"
},
{
"key": "Reticle",
"value": "Multiple"
},
{
"key": "Field of View",
"value": "8.78 x 7.03 Degrees"
},
{
"key": "Resolution",
"value": "640x512"
},
{
"key": "Dimensions",
"value": "8.3\" x 2.9\" x 4.3\""
},
{
"key": "Eye Relief",
"value": "45mm"
},
{
"key": "Zoom",
"value": "Digital 1x / 2x / 4x / 8x"
},
{
"key": "Proofs",
"value": "Shockproof / Waterproof"
},
{
"key": "Detection Range",
"value": "2500 yds"
},
{
"key": "Palettes",
"value": "Black, Red, White Hot, Fusion"
},
{
"key": "Battery Life",
"value": "Up to 4.5 h"
},
{
"key": "Battery Type",
"value": "18650 (3.7V) Lithium Rechargeable Battery"
},
{
"key": "Weight",
"value": "1.59 lbs"
},
{
"key": "Display",
"value": "0.39\" 1024x768 OLED"
}
]
},
{
"id": 2,
"brand": "AGM Global Vision",
"category": "Thermal Scopes",
"series": "Rattler",
"model": "TS35-384",
"status": "In Stock",
"mapp": 1799,
"msrp": 1995,
"qty": 7,
"image": "/img/products/agm-rattler-ts35-384.jpg",
"shelf_tag": "/docs/agm-rattler-ts35-384-shelftag.pdf",
"spec_sheet": "/docs/agm-rattler-ts35-384-specs.pdf",
"description": "Compact thermal riflescope with 384x288 sensor for mid-range hunting.",
"specs": [
{
"key": "Magnification",
"value": "2.0x"
},
{
"key": "Reticle",
"value": "Multiple"
},
{
"key": "Field of View",
"value": "10.0 x 8.0 Degrees"
},
{
"key": "Resolution",
"value": "384x288"
},
{
"key": "Dimensions",
"value": "7.4\" x 2.3\" x 3.2\""
},
{
"key": "Eye Relief",
"value": "45mm"
},
{
"key": "Zoom",
"value": "Digital 1x / 2x / 4x"
},
{
"key": "Proofs",
"value": "Shockproof / Waterproof"
},
{
"key": "Detection Range",
"value": "1200 yds"
},
{
"key": "Palettes",
"value": "White Hot, Black Hot, Fusion"
},
{
"key": "Battery Life",
"value": "Up to 4.5 h"
},
{
"key": "Battery Type",
"value": "CR123A / 18650 (adapter)"
},
{
"key": "Weight",
"value": "0.95 lbs"
},
{
"key": "Display",
"value": "0.39\" 1024x768 OLED"
}
]
}
]
}
Check the page and the json attached to this post to see how to setup a repeat region and data detail using one modal.
Archive.zip (2.8 KB)