Web Component
Example applications are a great way to explore the headless capabilities of Adobe Experience Manager (AEM). This Web Component application demonstrates how to query content using AEM’s GraphQL APIs using persisted queries and render a portion of UI, accomplished using pure JavaScript code.
View the source code on GitHub
Prerequisites prerequisites
The following tools should be installed locally:
AEM requirements
The Web Component works with the following AEM deployment options.
- AEM as a Cloud Service
- Local set up using the AEM Cloud Service SDK
- Requires JDK 11 (if connecting to local AEM 6.5 or AEM SDK)
This example app relies on basic-tutorial-solution.content.zip to be installed and the required deployment configurations are in place.
person.js
file.How to use
-
Clone the
adobe/aem-guides-wknd-graphql
repository:code language-shell $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
-
Navigate to
web-component
sub-directory.code language-shell $ cd aem-guides-wknd-graphql/web-component
-
Edit the
.../src/person.js
file to include the AEM connection details:In the
aemHeadlessService
object, update theaemHost
to point to your AEM Publish service.code language-plain # AEM Server namespace aemHost=https://publish-p123-e456.adobeaemcloud.com # AEM GraphQL API and Persisted Query Details graphqlAPIEndpoint=graphql/execute.json projectName=my-project persistedQueryName=person-by-name queryParamName=name
If connecting to an AEM Author service, in the
aemCredentials
object, provide local AEM user credentials.code language-plain # For Basic auth, use AEM ['user','pass'] pair (for example, when connecting to local AEM Author instance) username=admin password=admin
-
Open a terminal and run the commands from
aem-guides-wknd-graphql/web-component
:code language-shell $ npm install $ npm start
-
A new browser window opens the static HTML page that embeds the Web Component at http://localhost:8080.
-
The Person Info Web Component is displayed on the web page.
The code
Below is a summary of how the Web Component is built, how it connects to AEM Headless to retrieve content using GraphQL persisted queries, and how that data is presented. The complete code can be found on GitHub.
Web Component HTML tag
A reusable Web Component (aka custom element) <person-info>
is added to the ../src/assets/aem-headless.html
HTML page. It supports host
and query-param-value
attributes to drive the behavior of the component. The host
attribute’s value overrides aemHost
value from aemHeadlessService
object in person.js
, and query-param-value
is used to select the person to render.
<person-info
host="https://publish-p123-e456.adobeaemcloud.com"
query-param-value="John Doe">
</person-info>
Web Component implementation
The person.js
defines the Web Component functionality and below are key highlights from it.
PersonInfo element implementation
The <person-info>
custom element’s class object defines the functionality by using the connectedCallback()
life-cycle methods, attaching a shadow root, fetching GraphQL persisted query, and DOM manipulation to create the custom element’s internal shadow DOM structure.
// Create a Class for our Custom Element (person-info)
class PersonInfo extends HTMLElement {
constructor() {
...
// Create a shadow root
const shadowRoot = this.attachShadow({ mode: "open" });
...
}
...
// lifecycle callback :: When custom element is appended to document
connectedCallback() {
...
// Fetch GraphQL persisted query
this.fetchPersonByNamePersistedQuery(headlessAPIURL, queryParamValue).then(
({ data, err }) => {
if (err) {
console.log("Error while fetching data");
} else if (data?.personList?.items.length === 1) {
// DOM manipulation
this.renderPersonInfoViaTemplate(data.personList.items[0], host);
} else {
console.log(`Cannot find person with name: ${queryParamValue}`);
}
}
);
}
...
//Fetch API makes HTTP GET to AEM GraphQL persisted query
async fetchPersonByNamePersistedQuery(headlessAPIURL, queryParamValue) {
...
const response = await fetch(
`${headlessAPIURL}/${aemHeadlessService.persistedQueryName}${encodedParam}`,
fetchOptions
);
...
}
// DOM manipulation to create the custom element's internal shadow DOM structure
renderPersonInfoViaTemplate(person, host){
...
const personTemplateElement = document.getElementById('person-template');
const templateContent = personTemplateElement.content;
const personImgElement = templateContent.querySelector('.person_image');
personImgElement.setAttribute('src',
host + (person.profilePicture._dynamicUrl || person.profilePicture._path));
personImgElement.setAttribute('alt', person.fullName);
...
this.shadowRoot.appendChild(templateContent.cloneNode(true));
}
}
Register the <person-info>
element
// Define the person-info element
customElements.define("person-info", PersonInfo);
Cross-origin resource sharing (CORS)
This Web Component relies on an AEM-based CORS configuration running on the target AEM environment and assumes that the host page runs on http://localhost:8080
in development mode and below is a sample CORS OSGi configuration for the local AEM Author service.
Please review deployment configurations for respective AEM service.