Implement folding
Implement folding
This is for:
DeveloperCoveo Atomic lets you display search results that have a parent-child relationship with any level of nesting.
This article explains how to build hierarchical result lists using the atomic-folded-result-list component.
Prerequisites
Before indexing data, make sure that the data you’re working with has established parent-child relationships. Some data might already have these relationships when you collected it. If not, you’ll need to build a relationship graph yourself.
|
|
Note
You can’t create parent-child relationships directly in the Coveo Administration Console. The target metadata exist in the items you want to index, this could require you to implement the necessary data processing in your own infrastructure. |
Once your data has established parent-child relationships codified in the target metadata, create the proper folding fields and mappings for the target items, and index your content.
The fields you specify for collection-field, parent-field, and child-field must exist on the target items.
Main features
The atomic-folded-result-list component is similar to the atomic-result-list component, but provides extra functionality.
This component requires no extra configuration apart from specifying the three folding fields that were configured for these items:
-
collection-field -
parent-field -
child-field
It’s recommended to provide atomic-folded-result-list one or more atomic-result-template components to display the results.
Each result template can include an atomic-result-children component with nested atomic-result-children-template components to render the child results.
Basic structure
The following example shows an atomic-folded-result-list with parent and child result templates, including grandchild rendering through inherit-templates:
<atomic-folded-result-list
collection-field="foldingcollection"
parent-field="foldingparent"
child-field="foldingchild"
number-of-folded-results="2"
>
<atomic-result-template must-match-sourcetype="YouTube">
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
</template>
</atomic-result-template>
<atomic-result-template must-match-sourcetype="Slack">
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
<atomic-result-section-bottom-metadata>
<atomic-result-fields-list>
<atomic-result-text field="author"></atomic-result-text>
</atomic-result-fields-list>
</atomic-result-section-bottom-metadata>
<atomic-result-section-children>
<atomic-result-children image-size="icon">
<p slot="before-children">Attached files:</p>
<atomic-result-children-template must-match-filetype="pdf">
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
</template>
</atomic-result-children-template>
</atomic-result-children>
</atomic-result-section-children>
</template>
</atomic-result-template>
<atomic-result-template>
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
<atomic-result-section-children>
<atomic-result-children image-size="icon">
<atomic-result-children-template>
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
<atomic-result-section-children>
<atomic-result-children inherit-templates>
</atomic-result-children>
</atomic-result-section-children>
</template>
</atomic-result-children-template>
</atomic-result-children>
</atomic-result-section-children>
</template>
</atomic-result-template>
</atomic-folded-result-list>
Details
Use atomic-folded-result-list instead of atomic-result-list to enable folding. |
|
Specify your folding fields. These map to filterField, parentField, and childField in the Search API. |
|
This template only applies to YouTube results. Because it has no atomic-result-children, children are ignored for YouTube results. |
|
| This template applies to Slack results. It includes children rendering. | |
The before-children slot renders content only when children exist. |
|
Use must-match-filetype to conditionally render only PDF attachments as children. |
|
| A default result template applies to any result that doesn’t match the templates above. | |
The atomic-result-section-children section is where child results appear. |
|
atomic-result-children handles the display of child results and the "Show more"/"Show less" toggle. |
|
| Define a template for child results. | |
Nest another atomic-result-children for grandchild rendering. Set inherit-templates to reuse the child template. |
Grandchild elements
To render grandchildren, nest an additional atomic-result-children inside a child template.
Alternatively, if the inherit-templates property is set on a atomic-result-children component, the grandchild will use the template from its immediate element parent for rendering elements.
<atomic-result-children-template>
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
<atomic-result-section-children>
<atomic-result-children inherit-templates>
</atomic-result-children>
</atomic-result-section-children>
</template>
</atomic-result-children-template>
Nest another atomic-result-children for grandchild rendering. Set inherit-templates to reuse the child template. |
The grandchild rendering depends on templates and the value of the inherit-templates option.
For example:
-
The child defines template 1 and template 2; the grandchild defines template 3 and has
inherit-templates="true". The grandchild will use the templates in the following order:-
Template 3 (defined at the grandchild level)
-
Template 1 and template 2 (both defined at the child level, in this order)
-
-
The child defines template 1 and template 2; the grandchild defines template 3 and
inherit-templatesis set to"false"or not specified. The grandchild will only use template 3 and ignore the other two.
Conditional templates
You can define multiple atomic-result-template elements that apply to different source types.
Templates are only available within the scope in which they’re defined.
The following example uses must-match-sourcetype to render YouTube and Slack results differently, with Slack results showing children filtered by file type:
<atomic-result-template must-match-sourcetype="YouTube">
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
</template>
</atomic-result-template>
<atomic-result-template must-match-sourcetype="Slack">
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
<atomic-result-section-bottom-metadata>
<atomic-result-fields-list>
<atomic-result-text field="author"></atomic-result-text>
</atomic-result-fields-list>
</atomic-result-section-bottom-metadata>
<atomic-result-section-children>
<atomic-result-children image-size="icon">
<p slot="before-children">Attached files:</p>
<atomic-result-children-template must-match-filetype="pdf">
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
</template>
</atomic-result-children-template>
</atomic-result-children>
</atomic-result-section-children>
</template>
</atomic-result-template>
This template only applies to YouTube results. Because it has no atomic-result-children, children are ignored for YouTube results. |
|
| This template applies to Slack results. It includes children rendering. | |
The before-children slot renders content only when children exist. |
|
Use must-match-filetype to conditionally render only PDF attachments as children. |
Complete example
The following is the complete, runnable page that combines all the folding concepts introduced earlier:
<!doctype html>
<html lang="en">
<head>
<script type="module" src="https://static.cloud.coveo.com/atomic/v3.59.0/atomic.esm.js"></script>
<link rel="stylesheet" href="https://static.cloud.coveo.com/atomic/v3.59.0/themes/coveo.css"/>
<script type="module" src="./folding-init.js"></script>
</head>
<body>
<atomic-search-interface id="search-interface">
<atomic-search-box></atomic-search-box>
<atomic-folded-result-list
collection-field="foldingcollection"
parent-field="foldingparent"
child-field="foldingchild"
number-of-folded-results="2"
>
<atomic-result-template must-match-sourcetype="YouTube">
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
</template>
</atomic-result-template>
<atomic-result-template must-match-sourcetype="Slack">
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
<atomic-result-section-bottom-metadata>
<atomic-result-fields-list>
<atomic-result-text field="author"></atomic-result-text>
</atomic-result-fields-list>
</atomic-result-section-bottom-metadata>
<atomic-result-section-children>
<atomic-result-children image-size="icon">
<p slot="before-children">Attached files:</p>
<atomic-result-children-template must-match-filetype="pdf">
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
</template>
</atomic-result-children-template>
</atomic-result-children>
</atomic-result-section-children>
</template>
</atomic-result-template>
<atomic-result-template>
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
<atomic-result-section-children>
<atomic-result-children image-size="icon">
<atomic-result-children-template>
<template>
<atomic-result-section-title>
<atomic-result-link></atomic-result-link>
</atomic-result-section-title>
<atomic-result-section-excerpt>
<atomic-result-text field="excerpt"></atomic-result-text>
</atomic-result-section-excerpt>
<atomic-result-section-children>
<atomic-result-children inherit-templates>
</atomic-result-children>
</atomic-result-section-children>
</template>
</atomic-result-children-template>
</atomic-result-children>
</atomic-result-section-children>
</template>
</atomic-result-template>
</atomic-folded-result-list>
</atomic-search-interface>
</body>
</html>
Details
| Load the Atomic library and default theme from the CDN. | |
| Load the initialization script. | |
Use atomic-folded-result-list instead of atomic-result-list to enable folding. |
|
Specify your folding fields. These map to filterField, parentField, and childField in the Search API. |
|
This template only applies to YouTube results. Because it has no atomic-result-children, children are ignored for YouTube results. |
|
| This template applies to Slack results. It includes children rendering. | |
The before-children slot renders content only when children exist. |
|
Use must-match-filetype to conditionally render only PDF attachments as children. |
|
| A default result template applies to any result that doesn’t match the templates above. | |
The atomic-result-section-children section is where child results appear. |
|
atomic-result-children handles the display of child results and the "Show more"/"Show less" toggle. |
|
| Define a template for child results. | |
Nest another atomic-result-children for grandchild rendering. Set inherit-templates to reuse the child template. |
The initialization script sets up the search engine and triggers the first search:
// folding-init.js
import {getSampleSearchEngineConfiguration} from 'https://static.cloud.coveo.com/headless/v3.51.3/headless.esm.js';
(async () => {
await customElements.whenDefined('atomic-search-interface');
const searchInterface = document.querySelector(
'atomic-search-interface#search-interface'
);
if (!searchInterface) return;
await searchInterface.initialize({
...getSampleSearchEngineConfiguration(),
});
searchInterface.executeFirstSearch();
})();
Wait for the atomic-search-interface component to be registered. |
|
| Target the search interface element by its ID. | |
Replace with your own SearchEngineConfiguration. |
|
| Execute the initial search to populate the folded result list. |
For more details on defining result templates, see Displaying results.
Folding in rendering functions
Instead of using HTML templates to define how folded results render, you can write a custom rendering function.
A rendering function receives a FoldedResult object and returns rendered output for the result and its children.
In Atomic React, you pass this function through the template prop (for example, <AtomicFoldedResultList template={MyTemplate} />).
In other frameworks, you call the setRenderFunction() method on the atomic-folded-result-list DOM element.
|
|
Atomic React doesn’t support |
The following is a example that uses a rendering function to perform folding in Atomic React:
import {
AtomicFoldedResultList,
AtomicResultFieldsList,
AtomicResultLink,
AtomicResultMultiValueText,
AtomicResultSectionBottomMetadata,
AtomicResultSectionChildren,
AtomicResultSectionExcerpt,
AtomicResultSectionTitle,
AtomicResultText,
AtomicSearchBox,
AtomicSearchInterface,
} from '@coveo/atomic-react';
import type {FoldedResult} from '@coveo/headless';
import {
buildSearchEngine,
getSampleSearchEngineConfiguration,
} from '@coveo/headless';
import {type FunctionComponent, useMemo} from 'react';
export const FoldedResultListPage: FunctionComponent = () => {
const engine = useMemo(
() =>
buildSearchEngine({
configuration: getSampleSearchEngineConfiguration(),
}),
[]
);
return (
<AtomicSearchInterface engine={engine}>
<AtomicSearchBox />
<AtomicFoldedResultList template={MyTemplate} />
</AtomicSearchInterface>
);
};
function MyTemplate(result: FoldedResult) {
return (
<>
<AtomicResultSectionTitle>
<AtomicResultLink />
</AtomicResultSectionTitle>
<AtomicResultSectionExcerpt>
<AtomicResultText field="excerpt" />
</AtomicResultSectionExcerpt>
<AtomicResultSectionChildren>
{!!result.children.length && (
<div>
<strong>Child results:</strong>
<ul>
{result.children.map((child, i) => (
<li key={child.result.uniqueId}>
<strong>Child {i + 1}: </strong>
<a href={child.result.clickUri}>{child.result.title}</a>
</li>
))}
</ul>
</div>
)}
</AtomicResultSectionChildren>
<AtomicResultSectionBottomMetadata>
<AtomicResultFieldsList>
{Boolean(result.result.raw.author) && (
<div className="field">
<span className="field-label">Author: </span>
<AtomicResultText field="author" />
</div>
)}
{Boolean(result.result.raw.language) && (
<div className="field">
<span className="field-label">Language: </span>
<AtomicResultMultiValueText field="language" />
</div>
)}
</AtomicResultFieldsList>
</AtomicResultSectionBottomMetadata>
</>
);
}
| Import the Atomic React components. In React, you use JSX wrappers instead of web component tags. | |
FoldedResult is the type passed to your rendering function. It contains result (the current item) and children (an array of FoldedResult). |
|
Create a search engine instance using the sample configuration from @coveo/headless. |
|
Pass a template function to AtomicFoldedResultList. This function receives a FoldedResult and returns JSX. |
|
The template function receives the full FoldedResult object, giving you access to result.children for rendering child items. |
|
Use AtomicResultSectionChildren to define where child results appear. Access result.children directly to render them with custom JSX. |