Global truncate code for any element

Topic summary

A user is implementing a truncate + “Read More” functionality across their Shopify store. The JavaScript code works correctly for product descriptions but fails when applied to Rich Text sections using Metaobject values.

Current behavior:

  • Product template: Functions as expected, showing truncated text with expand/collapse
  • Metaobject template: Element completely disappears when clicking “Read More” instead of displaying full content

Code structure:

  • JavaScript in theme.liquid toggles visibility between truncated-description and full-description divs
  • Uses click event listeners on read-more and read-less elements
  • CSS hides full-description by default

Proposed solution:
Another user suggests wrapping the script in DOMContentLoaded event listener and adding null checks to ensure all required elements exist before attaching event listeners. This prevents errors when elements aren’t present on the page.

The issue likely stems from timing problems or missing elements when the script runs on metaobject pages.

Summarized with AI on November 4. AI used: claude-sonnet-4-5-20250929.

I have a code I’m utilising to truncate + “Read More” across different elements in my store. It’s working perfectly for product descriptions, but not when I’m trying to use it on a “Rich Text” section with a Metaobject value.

Script in theme.liquid:

<script>
let read_more = document.getElementById('read-more')
let read_less = document.getElementById('read-less');
let truncated_description = document.getElementById('truncated-description');
let full_description = document.getElementById('full-description');

read_more.addEventListener('click', showHideDescription)
read_less.addEventListener('click', showHideDescription)

function showHideDescription(){
  let ID = this.id
  if(ID === "read-more"){
    truncated_description.style.display = "none";
    full_description.style.display = "block";
  }else {
    truncated_description.style.display = "block";
    full_description.style.display = "none";    
  }
}
</script>

CSS in base.css:

.truncate-container {
  width: 100%;
}
.read-additional {
  text-decoration: underline;
}
.read-additional:hover {
  cursor: pointer;
}
#full-description {
  display: none;
}
#read-more {
  font-weight: 500;
}
#read-less {
  font-weight: 500;
}

Custom Liquid in product template - this works, has some different conditions so ignore those:

{% if product.description.size > 150 %}
<div class="truncate-container">
<div id="truncated-description">{{ product.description | strip_html | truncate: 150 }} <span id="read-more" class="read-additional">Read more</span></div>
<div id="full-description">
{{ product.description }} <p><span id="read-less" class="read-additional">Read less</span></p></div>
</div>
{% else %}
{{ product.description }}
{% endif %}

Custom Liquid in metaobject template - this works until hitting “Read more”, which causes the element to disappear completely instead of displaying full description:

<div class="truncate-container">
<div id="truncated-description">{{ metaobject.main_copy | truncate: 500 }} <span id="read-more" class="read-additional">Read more</span></div>
<div id="full-description">
{{ metaobject.main_copy }} <p><span id="read-less" class="read-additional">Read less</span></p></div>
</div>

Hello @TeTx ,

You can try the following scripts:

I hope this helps. Let me know if you have any other questions.

Best regards,
Liz