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.
| Property | Type | What it is |
|---|---|---|
cmlLocator | string | The name you gave it in Flex, or '' if it has none. |
componentType | string | Its type, e.g. 'cml-text'. |
cmlId | string | Its internal id, or '' if unset. |
capabilities | CapabilityName[] | 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.
| Namespace | On | Methods |
|---|---|---|
media | cml-video | play(), pause() |
text | cml-text | setText(text), getText() |
states | Any visible element | activate(name), deactivate(name), toggle(name), list(), current() |
visibility | Any visible element | show(), hide(), isHidden() |
pages | The experience | list(), 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.