Skip to main content

ProductDescription

Renders a product's HTML description with optional truncation and expand/collapse functionality. Resolves the correct localized description from the product's descriptions array and renders it as raw HTML using dangerouslySetInnerHTML.


Usage

Basic usage

import ProductDescription from '@/components/propeller/ProductDescription';

<ProductDescription product={product} />

With a specific language

<ProductDescription
product={product}
language="EN"
/>

Collapsed with truncation

Show the first 300 characters with a "Read more" toggle to expand.

<ProductDescription
product={product}
language="NL"
collapsed={true}
maxLength={300}
/>

Collapsed with a short preview

<ProductDescription
product={product}
collapsed={true}
maxLength={150}
className="my-8"
/>

Cluster product

The component accepts both Product and Cluster objects. Both share the same descriptions field structure.

<ProductDescription
product={cluster}
language="EN"
collapsed={true}
maxLength={500}
/>

Custom styling

<ProductDescription
product={product}
className="border-t pt-6 mt-6"
/>

Configuration

Required

PropTypeDescription
productProduct | ClusterProduct or Cluster object. The component reads the descriptions array to find the matching localized entry

Localization

PropTypeDefaultDescription
languagestring'NL'Language code used to resolve the correct entry from product.descriptions. Falls back to the first available description if no match is found

Truncation

PropTypeDefaultDescription
collapsedbooleanfalseWhen true, the description is initially collapsed to maxLength characters with a "Read more" toggle
maxLengthnumber0Maximum number of plain-text characters shown when collapsed. 0 disables truncation entirely, even when collapsed is true

Appearance

PropTypeDefaultDescription
classNamestring--Extra CSS class applied to the root <div> element

Behavior

HTML rendering

The description value is rendered as raw HTML via dangerouslySetInnerHTML. The rendered content is wrapped in a div with Tailwind typography classes (prose prose-slate max-w-none text-muted-foreground), so standard HTML elements like headings, paragraphs, lists, and links are styled automatically.

Truncation

Truncation only activates when all three conditions are met:

  1. collapsed is true
  2. maxLength is greater than 0
  3. The plain-text length of the description exceeds maxLength

When truncating, the component:

  • Strips all HTML tags to produce a plain-text version.
  • Cuts the text at maxLength characters.
  • Snaps backward to the last word boundary to avoid cutting mid-word.
  • Appends an ellipsis character.

The truncated version is rendered as plain text (not HTML), so any formatting, links, or images from the original description are removed in the collapsed state.

Expand / Collapse

When truncation is active, a toggle button appears below the description text:

  • "Read more" -- Expands the description to show the full HTML content.
  • "Read less" -- Collapses back to the truncated plain-text preview.

The toggle button is styled as a text link (text-primary hover:underline).

Empty state

If the product has no descriptions array, or if no matching language entry is found and there is no fallback entry, the component renders nothing (the entire root element is hidden).

Reactivity

The component re-evaluates the description whenever the product or language prop changes. Switching products or languages resets the resolved HTML and re-applies truncation rules.


GraphQL Query

When fetching a product, include the descriptions field to supply this component with data:

query Product(
$productId: Int!
$language: String
) {
product(id: $productId) {
productId
sku
names(language: $language) { value language }
descriptions(language: $language) { value language }
}
}

Variables:

{
"productId": 42,
"language": "NL"
}

For a cluster:

query Cluster(
$clusterId: Int!
$language: String
) {
cluster(id: $clusterId) {
clusterId
names(language: $language) { value language }
descriptions(language: $language) { value language }
}
}

Note: Even when requesting a specific language in the query, the API may return multiple localized entries. The component performs its own language matching on the returned array.


SDK Services

This component does not call any SDK services directly. It reads data from a Product or Cluster object that has already been fetched.

Product fields used

FieldTypePurpose
product.descriptionsLocalizedString[]Array of localized description entries. Each entry has language (string) and value (string, may contain HTML)

The component resolves the description in this order:

  1. Finds the first entry in descriptions where language matches the language prop.
  2. If no match, falls back to descriptions[0].value.
  3. If descriptions is empty or missing, renders nothing.