Experience Components
Overview
A component is the fundamental building block of a Purple Experience view. Every visible element, a list of articles, a navigation bar, a button, and an image, is a component. Components are declared as JSON objects inside views.json and are identified by a type field. They all share a common set of base configuration properties (id, class, template, sticky, etc.) and can be conditionally shown or hidden at runtime.
When to use this
Read this page to understand how any component is configured. The properties documented here apply to every component type. list, section, html, swiper, subscription, content, and all others. Type-specific properties are documented on each component's own page.
Basic Example
{
"type": "html",
"template": "headline",
"id": "page-title",
"class": "text-primary",
"content": [{ "type": "html", "tag": "h1", "text": "Latest News" }]
}This renders an html component using the headline template, assigns the element id="page-title" and CSS class text-primary. The template value is also set as an HTML attribute (template="headline") so CSS selectors like html-component[template="headline"] can target it.
Configuration
All components inherit a base configuration. These properties apply to every component type.
Property | Type | Default | Description |
|---|---|---|---|
type | string | - | Required. Identifies which component to render (e.g., list, section, html, swiper) |
template | string | - | Template variant to use. Controls layout; also set as an HTML attribute for CSS targeting |
id | string | - | Sets the HTML id attribute on the element. Also used as the tracking key. Supports conditional values |
class | string | array | - | CSS class(es) to assign. Accepts a string, an array of strings, or conditional values |
sticky | boolean | false | Makes the element CSS-sticky |
isLazy | boolean | - | When true, the component is only initialized when it enters the viewport |
skipSSR | boolean | false | Skip server-side rendering for this component. Renders only on the client |
attributes | object | - | Custom HTML attributes - See Attributes below |
condition | object | - | Condition that must be true for the component to render. See Conditions |
class with conditional values
The class property supports conditional values, making it possible to apply CSS classes based on runtime context:
{
"type": "html",
"class": {
"value": "highlight",
"condition": {
"value": "$context.issue.purchased",
"operation": "EQUALS",
"compareValue": "true"
},
"fallback": "locked"
}
}Multiple classes can be combined using an array, where each entry can be a plain string or a conditional value:
{
"type": "html",
"class": [
"base-card",
{
"value": "is-new",
"condition": { "value": "$context.issue.isNew", "operation": "EQUALS", "compareValue": "true" }
}
]
}attributes
The attributes property adds HTML attributes to the component element.
{
"type": "html",
"attributes": {
"aria": {
"label": "Close dialog",
"expanded": "false"
},
"data": {
"tracking-id": "hero-banner"
},
"html": {
"role": "button",
"popover": "auto"
}
}
}Sub-property | Description |
|---|---|
aria | Adds aria-* attributes. Keys are automatically prefixed with aria- if not already |
data | Adds data-* attributes. Keys are automatically prefixed with data- if not already |
html | Arbitrary HTML attributes (role, popover) |
condition
The condition property controls whether the component is rendered at all. When the condition evaluates to false, the component is completely removed from the DOM — it is not hidden with CSS, it is not mounted.
{
"type": "subscription",
"condition": {
"value": "$context.platform",
"operation": "EQUALS_NOT",
"compareValue": "WEB"
}
}
For more details, see Conditions
Advanced Features
isLazy
Lazy components are not initialized until they scroll into view. This is useful for heavy below-the-fold components to improve initial load performance. The component renders ghost placeholders until it enters the viewport. The component's host element must have a box of its own to be detected in the viewport, see "Component hosts need their own box" under Testing Notes / Edge Cases.
skipSSR
When true, the component is completely skipped during server-side rendering. This is useful for components that depend on browser APIs or user-specific state that is not available on the server (e.g., ads or components that read from localStorage).
Template targeting in CSS
The template value is set as both an Angular class binding and an HTML attribute. This lets you use attribute selectors in CSS:
my-component[template='card'] {
display: grid;
}
my-component[template='list-item'] {
display: flex;
}Component types available
Type | Description |
|---|---|
section | Wraps other components - primary layout container |
list | Renders a repeated component for each item in a data source |
swiper | Horizontally scrollable list based on Swiper.js |
html | Renders an HTML element with a given tag |
content | Displays a single catalog content item (article, issue) |
publication | Displays a single publication |
subscription | Displays a subscription plan |
search-field | Text input for full-text search |
search-result | Displays a single search result |
login | Login form using Purple Entitlement |
dropdown | Dropdown select element |
toggle | Toggle switch |
switch | Conditional component switcher |
bookmark | Bookmark button for content |
toolbar | Toolbar with action buttons |
menu | Navigation menu from the Catalog API |
widget | Embeds an external widget |
action-executor | Runs actions on component init |
ad | Displays a single ad slot |
Testing Notes / Edge Cases
- condition false = not mounted: A component with a false condition is fully removed from the DOM. Data sources inside it are not initialized. If you are checking whether a list loaded data, first confirm its condition is true.
- class conditional with no fallback: If the condition is false and no fallback is set, the class is not applied and no error is thrown. The element will have no class at all from that entry.
- id uniqueness: If multiple instances of the same component appear (e.g. inside a list), avoid setting a static id it will produce duplicate HTML IDs.
- template attribute: The template attribute is set as a string on the host element. CSS selectors using it are case-sensitive.
- Component hosts need their own box: Components wait until their host element is in view before they load data (lists, content, images, elements, ads, issue search results, and sections after in-app navigation). A host styled display: contents has no box of its own and is never reported as visible, so the component stays on its placeholder after navigating within the app. Opening the page directly still works, because it is rendered on the server. Put layout rules on the host itself (e.g. display: flex or display: grid, see Template targeting in CSS), or use display: contents only on inner wrappers such as .list-content.
Related Topics
- Data Sources Overviewdata