Skip to main content

Component

A Component is one component on your published page. It gives you a stable, supported surface for reading and driving that component, so you don't have to reach into the DOM.

You get one from a ComponentSet — via .only(), .first(), .nth(i), or iteration — or as event.target in an event handler.

const hero = experience.findByLocator('hero').only()

hero.componentType // 'cml-text'
hero.cmlLocator // 'hero'
hero.text.setText('Welcome')

Everything on a component falls into one of four groups: identity, attributes and data, capabilities, and events.

Identity

Read-only properties describing the component.

PropertyTypeWhat it is
cmlLocatorstringThe name you gave it in Flex, or '' if it has none.
componentTypestringIts type, e.g. 'cml-text'.
cmlIdstringIts internal id, or '' if unset.
capabilitiesCapabilityName[]Which capabilities it carries, e.g. ['text', 'states', 'visibility'].
if (hero.componentType === 'cml-video') hero.media.play()

has(capability)

has(capability: CapabilityName): boolean

Check for a capability before using it. CapabilityName is 'media' | 'text' | 'states' | 'visibility' | 'pages'.

if (hero.has('media')) hero.media.play()

Optional chaining does the same job more briefly:

hero.media?.play() // does nothing if hero isn't a video

Capabilities

What a component can do depends on its type. A capability namespace exists only when the component carries it; otherwise the property is undefined.

NamespaceOnMethods
mediacml-videoplay(), pause()
textcml-textsetText(text), getText()
statesAny visible elementactivate(name), deactivate(name), toggle(name), list(), current()
visibilityAny visible elementshow(), hide(), isHidden()
pagesThe experiencelist(), current(), goTo(slugOrIndex), next(), previous()
const video = experience.findByTag('cml-video').first()

video?.media.pause()
video?.visibility.hide()

See Capabilities for each one in full.

Attributes

getAttribute(name: string): string | undefined
setAttribute(name: string, value: string | null): void

Read and write HTML attributes on the component.

const link = experience.findByLocator('cta-link').only()

link.getAttribute('href') // 'https://…', or undefined if absent
link.setAttribute('data-seen', '1')
link.setAttribute('data-seen', null) // passing null removes it

On a set, setAttribute applies to every member and getAttribute reads the first — see how calls fan out.

Two attribute families are off-limits and throw if you try to write them: cml-id, which identifies the component and can't change, and anything starting with editor-, which exists only while authoring and never reaches a published page. Both are readable.

Author data

getData(key: string): string | undefined
setData(key: string, value: string | null): void

Key-value data attached to an element in Flex's SDK Data inspector. This is the clean way to pass values from the design to your code — a product SKU, a price, a video id — without hard-coding them in the script.

Data lives under a reserved data-sdk- prefix, so getData('color') reads data-sdk-color. That keeps it separate from Ceros' own attributes: you only ever read back what was put there deliberately.

const card = experience.findByLocator('card').only()

card.getData('sku') // 'ABC-123', or undefined if the key isn't set
card.setData('sku', 'XYZ-789')
card.setData('sku', null) // removes it
// a common pattern: read per-element config set by whoever built the design
experience.findByLocator('product').forEach((product) => {
fetchPrice(product.getData('sku')).then((price) => {
product.findByLocator('price').text.setText(price)
})
})

Events

on(type: SdkEventType, handler: (event: ComponentEvent) => void): Unsubscribe

Subscribe to a runtime event on this component. Returns a function you call to stop listening. Events bubble, so a listener on a container also fires for everything inside it.

const off = hero.on('component.click', (event) => {
console.log('clicked', event.target.cmlLocator)
})

off() // stop listening

Full detail — event types, payload, and patterns — in Events.

Searching inside a component

The same three lookups as your experience handle, scoped to this component's contents (the component itself is never a match):

findByLocator(locator: string): ComponentSet
findByTag(tag: string): ComponentSet
findById(id: string): ComponentSet
const pricing = experience.findByLocator('pricing').only()

pricing.findByTag('cml-text') // only the text inside the pricing section

See Finding components.

getElement()

getElement(): Element

The escape hatch to the underlying DOM element, for the rare thing the SDK doesn't cover — measuring layout, reading computed styles, attaching a listener for an event the SDK doesn't expose.

const rect = hero.getElement().getBoundingClientRect()

Prefer the capabilities, properties, and on(...) where they cover what you need: they're the supported surface, and they won't change under you. Writing directly to the element — setting textContent on a text component, for example — can corrupt what Ceros renders.

Runtime only

Everything a component lets you change — text, visibility, states, attributes, data — changes the live page and nothing else. It is never saved back to your experience, and a reload restores exactly what was published. See Limits.

wrap(element)

wrap(element: Element): Component

Wraps a DOM element as a Component. Lookups already do this for you, so you'll rarely need it — mainly useful in tests where you have an element in hand.