Migrating to Web SDK 26.3.0
Version 26.3.0 of the Atomic Web SDK changes how stream containers are rendered on your page. Earlier versions rendered each container inside an iframe. From 26.3.0, containers render inside a shadow root attached to the element you provide. Overflow menus, dropdowns and date pickers are no longer clipped by the edge of the container.
The public AtomicSDK API is otherwise unchanged, apart from the removal of some deprecated configuration options and methods (see Removed configuration options and methods). The same methods, arguments, callbacks and configuration continue to work.
You don't need to make any changes if your integration:
- only calls current
AtomicSDKmethods, - does not use any of the removed options or methods,
- does not style or observe the SDK's iframes or internal elements,
- does not set a Content Security Policy, and
- is not a Cordova or Capacitor app.
Otherwise, work through the sections below. Each one describes a change that may require action, with before and after examples.
Load a single script
The SDK now ships as a single sdk.js file. Earlier versions also used a second script, iframe-manager.js, to render content inside each iframe. In a web page, the SDK loaded this script from the Atomic CDN automatically. In a Cordova or Capacitor app, you bundled it with your app and added it to your page with the ID atomic-frame-manager.
From 26.3.0, the SDK no longer loads a second script from the Atomic CDN at runtime, whether you install it from the CDN or from npm.
Action required (Cordova and Capacitor only): remove the iframe-manager.js script tag and the file itself, and keep only sdk.js.
<!-- Before -->
<script src="js/iframe-manager.js" id="atomic-frame-manager"></script>
<script src="js/sdk.js"></script>
<!-- After -->
<script src="js/sdk.js"></script>
If you integrate the SDK in a web page, no action is required. See Installation for details.
Target the container by type
Earlier versions let you target a container's iframe by its type, for example iframe.single-card. The container is no longer an iframe. Instead, for standalone and single card containers, the SDK adds the class atomic-sdk-frame, plus the container type (standalone or single-card), to your host element: the element you pass to embed or singleCard.
The SDK already adds these classes to the elements it creates for the launcher (atomic-sdk-frame launcher) and modal stream (atomic-sdk-frame modal-stream) containers.
The has-card class, which the single card iframe had while it was displaying a card, has also moved to your host element.
Action required: replace selectors that target the SDK's iframes with selectors that target your host element, or the launcher element.
/* Before */
#embed iframe.single-card.has-card { … }
iframe.atomic-sdk-frame.launcher { … }
/* After */
#embed.atomic-sdk-frame.single-card.has-card { … }
.atomic-sdk-frame.launcher { … }
This applies to any selector that reached the container through a descendant combinator, not only selectors that named iframe. The container is now the host element itself, so a space (descendant) combinator must become a compound selector on the host: #embed .atomic-sdk-frame.has-card (with a space) becomes #embed.atomic-sdk-frame.has-card (no space). A selector such as #embed .atomic-sdk-frame { … } silently stops matching otherwise.
When a container is stopped, the SDK removes only the classes it added, so a class with the same name that you added yourself is left in place.
Give the SDK an element whose class nothing else rewrites
Because these classes now live on your host element, the SDK writes to that element's class attribute — and it keeps writing to it while the container runs, as has-card, is-empty, has-subview and uploading-files come and go.
That conflicts with any code that also writes the element's class. If you render the host element with a framework and its class is recomputed — a React className that changes between renders, or a styled-components class that changes with props — the new value replaces the SDK's classes, and your selectors silently stop matching.
Action required: pass the SDK an element whose class nothing else sets. In React, that means an element you only attach a ref to:
const ref = useRef(null)
useEffect(() => {
const container = AtomicSDK.singleCard(ref.current, { … })
return () => container.stop()
}, [])
// No className: the SDK owns this element's classes.
return <div ref={ref} />
If you need your own classes or styling on the container, put them on a wrapper around the SDK's element rather than on the element itself:
return (
<div className={isWide ? 'panel wide' : 'panel'}>
<div ref={ref} />
</div>
)
The same applies to anything else that rewrites the attribute, such as element.className = … or a template that re-renders the element.
Position and size the modal overlay
Single card and horizontal containers present a card's subviews, full image and video views, and the snooze and feedback screens in a modal overlay. In earlier versions this was a separate iframe with the class modal-subview, which you positioned, sized and showed with your own CSS. The overlay is now rendered within the SDK, which shows and hides it, and you position it with CSS custom properties.
The overlay covers the viewport and places the modal using flexbox. --atomic-modal-subview-justify-content sets its horizontal position and --atomic-modal-subview-align-items sets its vertical position, using values such as flex-start, center and flex-end. By default the modal is centered, 480px wide (or 92% of the viewport width on narrow screens), with 20px of padding around the overlay.
Action required: replace modal-subview CSS with the --atomic-modal-subview-* custom properties, set on your host element or on :root. Remove any CSS that hides the iframe until it has the has-subview class.
/* Before */
#my-embed iframe.modal-subview {
position: fixed;
top: 20px;
left: 20px;
width: 400px;
max-height: 60%;
border-radius: 20px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.05);
opacity: 0;
pointer-events: none;
}
#my-embed iframe.modal-subview.has-subview {
opacity: 1;
pointer-events: auto;
}
/* After */
#my-embed {
--atomic-modal-subview-align-items: flex-start;
--atomic-modal-subview-justify-content: flex-start;
--atomic-modal-subview-width: 400px;
--atomic-modal-subview-max-height: 60vh;
--atomic-modal-subview-border-radius: 20px;
--atomic-modal-subview-box-shadow: 0 0 20px rgba(0, 0, 0, 0.05);
}
The alignment properties are flexbox properties, so use values such as flex-start, center and flex-end, not left or top. The full set of properties is listed in Overriding styles.
Detect when a subview is displayed
In earlier versions, the has-subview class was added to the modal subview iframe. It is now added to your host element, the element you pass to singleCard, or to embed for a horizontal container.
Action required (CSS): target the class on your host element instead of the iframe.
/* Before */
.modal-subview.has-subview { … }
/* After */
#my-embed.has-subview { … }
Action required (JavaScript): if you observe the class in script, observe your host element instead. Alternatively, use the SDK event observer, which also tells you which card and subview is displayed:
AtomicSDK.observeSDKEvents(event => {
if (event.eventName === 'card-subview-displayed') {
// event.properties.subviewId / subviewTitle / subviewLevel
// event.cardContext.cardInstanceId
}
if (event.eventName === 'card-subview-exited') {
// The subview has been closed
}
})
Detect when a file upload is in progress
In earlier versions, the uploading-files class was added to the modal subview iframe of a single card or horizontal container while a file upload was in progress. It is now added to your host element.
Action required: observe your host element instead of the modal subview iframe.
// Before
observer.observe(document.querySelector('#embed-container>.modal-subview'), {
attributeFilter: ['class']
})
// After
observer.observe(document.querySelector('#embed-container'), {
attributeFilter: ['class']
})
See File upload for a complete example.
Reposition toast messages
In earlier versions, you repositioned toast messages by styling the .toast-container iframe. This applied to single card and modal stream containers, and to standalone and launcher containers with the customToastContainer option enabled. That iframe no longer exists. Toast placement is now controlled with CSS custom properties.
Action required: replace .toast-container CSS with the --atomic-toast-* custom properties, set on your host element or on :root.
/* Before */
.toast-container {
bottom: 0;
right: 0;
max-width: 300px;
}
/* After */
#my-embed {
--atomic-toast-bottom: 0;
--atomic-toast-right: 0;
--atomic-toast-left: auto;
--atomic-toast-transform: none;
--atomic-toast-max-width: 300px;
}
Also note:
- Toast message text in single card and modal containers, and in standalone and launcher containers with
customToastPlacementenabled, is now centered by default. To left-align it, set--atomic-toast-text-align: left. Toast messages shown at the bottom of the card feed are unchanged and remain left-aligned. - The new
--atomic-toast-min-widthproperty stops short messages producing a very small toast in these containers. - The
customToastContainerconfiguration option has been renamedcustomToastPlacement. The old name still works but is deprecated. If you supply both,customToastPlacementtakes precedence.
// Before
AtomicSDK.launch({
...
enabledUiElements: {
customToastContainer: true
}
})
// After
AtomicSDK.launch({
...
enabledUiElements: {
customToastPlacement: true
}
})
See toast messages for details.
Give the container rounded corners
In earlier versions, border-radius on the container's iframe clipped the card to rounded corners. There is no iframe now, so set both border-radius and overflow: hidden on your host element instead. This is safe: the SDK's position: fixed content — the menus, toasts and subview overlay — is rendered in the browser's top layer, so overflow: hidden does not clip it.
#embed {
border-radius: 12px;
overflow: hidden;
}
Hide the card while a subview is open
This applies to single card containers. Vertical, launcher and modal stream containers don't present subviews in a modal overlay, so they never have the has-subview class. Horizontal containers do, but they also display other cards, which would be hidden as well.
Earlier versions let you hide the card behind an open subview by setting display: none on the card iframe. There is no separate card element now, and display: none or visibility: hidden on your host element also hides the subview overlay.
Instead, set the --atomic-card-visibility custom property, scoped to the subview with the has-subview class. It hides only the card feed; the subview overlay stays visible.
#embed.has-subview {
--atomic-card-visibility: hidden;
}
Anchor the subview overlay to the container
The subview overlay covers the viewport. To place it relative to the container instead, the SDK publishes the host element's live position and size as the --atomic-container-top, --atomic-container-left, --atomic-container-width and --atomic-container-height custom properties, kept up to date as the container is scrolled, resized, laid out differently, or animated into a new position. Combine them with the --atomic-modal-subview-* properties to position the overlay in CSS, without measuring the container yourself.
#embed {
--atomic-modal-subview-align-items: flex-start;
--atomic-modal-subview-justify-content: flex-start;
/* Place the overlay just below the container. */
--atomic-modal-subview-padding: calc(var(--atomic-container-top) + var(--atomic-container-height))
0 0 var(--atomic-container-left);
}
Update your Content Security Policy
The SDK no longer creates iframes, and image previews for file upload are rendered from blob: URLs.
Action required: if you set a Content Security Policy:
- Make sure
img-srcincludesblob:, so file upload image previews are displayed. A wildcard does not coverblob::*(and scheme wildcards such ashttps:) never match theblob:ordata:schemes, so a policy withimg-src *still has to listblob:explicitly, for exampleimg-src * blob:. - You can remove
frame-src blob:if nothing else on your page needs it. The SDK no longer requires it.
See Content Security Policy for the full list of directives.
Cordova and Capacitor
The single script and Content Security Policy changes apply to Cordova and Capacitor integrations.
Action required:
- Remove
iframe-manager.jsfrom your app bundle, and remove itsscripttag. - You can remove
<allow-navigation href="about:*" />from yourconfig.xmlfile if nothing else in your app needs it. The SDK no longer navigates toabout:URLs.
See Cordova/Capacitor SDK for the updated setup.
Removed configuration options and methods
Stream container features flags
Several features flags were deprecated in version 25.3.0, when they were moved to the top level of the stream container configuration. They have now been removed.
Action required: move each flag out of features to the top level of the configuration object.
// Before
AtomicSDK.embed(hostElement, {
streamContainerId: '1234',
features: {
cardMinimumHeight: 200,
horizontalContainerConfig: {enabled: true, cardWidth: 300},
controlledContainerOpenState: true
}
})
// After
AtomicSDK.embed(hostElement, {
streamContainerId: '1234',
cardMinimumHeight: 200,
horizontalContainerConfig: {enabled: true, cardWidth: 300},
controlledContainerOpenState: true
})
features.cordova and features.runtimeVariableAnalytics are unaffected and remain in features.
features.cardVoting
features.cardVoting has been removed with no SDK replacement. Card voting is configured in the Atomic Workbench, so it can no longer be set through the SDK. See card voting.
Action required: remove cardVoting from your configuration, and configure card voting on your cards in the Workbench.
AtomicSDK.sendEvent
AtomicSDK.sendEvent, deprecated since version 24.1.0, has been removed with no replacement.
Action required: remove any calls to AtomicSDK.sendEvent.
New in this version
The following changes don't require any action, but you may find them useful:
has-cardandis-emptyclasses: single card and horizontal containers add these classes to your host element, depending on whether a card is displayed.has-cardwas previously only available on the single card iframe, andis-emptyis new for both container types.- Toast overrides: the new
--atomic-toast-min-widthand--atomic-toast-text-aligncustom properties. See Overriding styles. - Container transforms are supported: you can place a container inside a transformed element, such as a drawer, and the SDK's menus, toasts and subview overlay stay correctly placed, with no action needed. See Overriding styles.
--atomic-card-visibility: hides the card feed while a subview is open. See Hide the card while a subview is open.- Container geometry custom properties:
--atomic-container-top,-left,-widthand-heightexpose the host element's live position and size, for anchoring the subview overlay in CSS. See Anchor the subview overlay to the container. - Flushing analytics events:
AtomicSDK.flushEventssends queued analytics events immediately, andAtomicSDK.setEventFlushIntervalconfigures how often they are sent over HTTP. See Flushing analytics events.