Methods
openSliderAppPage
async openSliderAppPage(params: any = {}): Promise<any>
The openSliderAppPage method allows you to open the current app in a new slider, passing arbitrary parameters.
How it works:
- Data Passing: You call the method and pass an object with parameters (e.g., place, action, or id).
- Processing in the Application: On the application side, it's most convenient to intercept these parameters through middleware. This allows you to decide which route to display to the user before the page is rendered.
- Seamless Navigation: The user sees a new slider with the desired content, while the redirection logic is hidden within the application.
Slider settings are passed via bx24_-prefixed keys. In particular, bx24_title sets the slider title; when the portal opens the slider it also reflects that title to the browser tab (document.title). So, unlike parent.setTitle (which only updates the in-layout #pagetitle), this path does change the browser tab title:
await $b24.slider.openSliderAppPage({ bx24_title: 'My title' })
What the portal does with your parameters
Three things worth knowing before you design around this call, because each has sent someone down a wrong path:
- The portal re-opens your own registered handler URL — not a portal path.
openPathis the one that opens a portal path, and pointing it at an application page yields a 404 on the portal side. That failure looks like "sliders cannot host application pages", which is not the case. - Everything in the argument object is forwarded to the new frame as
PLACEMENT_OPTIONS. Soplaceis an ordinary call parameter, not a registered placement — you do not needplacement.bindfor it, and you may name it whatever you like. bx24_widthhas a practical lower bound. Below your own mobile breakpoint a desktop slider silently renders your mobile layout.
Routing to the right screen once the frame opens is your application's job. The SDK's part ends when the parameter is delivered.
Routing to the right screen in Nuxt
The pattern below is the one to copy. It looks longer than a plain
return navigateTo(target) because two of its lines exist to survive a case that
returns no error when it fails.
DOMAIN, PROTOCOL, LANG, APP_SID); for a prerendered
page opened with a query, Nuxt hydrates on the bare path and then restores the
original URL on app:suspense:resolve by assigning router.currentRoute.value
directly — bypassing navigation guards, and overwriting whatever your middleware
redirected to. The slider stays on the page the portal opened, and nothing
reports an error.This is not limited to nuxt generate. nuxt build prerenders any route listed
in nitro.prerender.routes, and with crawlLinks: true anything reachable by a
link — so an app that looks like an ordinary SSR deployment can still ship a
prerendered slider entry point. Whether the file is served by a static web server
or by Nitro itself makes no difference; what matters is only whether the page
carries a prerendered payload.
// @check-ignore: Nuxt auto-imports (defineNuxtRouteMiddleware, navigateTo, onNuxtReady) plus two app-level helpers — none resolvable in the docs typecheck context
export default defineNuxtRouteMiddleware(async (to) => {
if (import.meta.server) return
const { $initializeB24Frame } = useNuxtApp()
const $b24 = await $initializeB24Frame()
const target = routeForPlace($b24.placement.options?.place)
if (!target || isSamePath(to.path, target)) return
// Take the query from the ADDRESS BAR, not from `to.query`: a prerendered page
// hydrates on the bare path, so `to` carries no query at all and the target
// screen would lose `place` along with the portal's own parameters.
const dest = { path: target, query: Object.fromEntries(new URLSearchParams(location.search)) }
const nuxtApp = useNuxtApp()
// Live navigation inside an already running app — the ordinary way works.
if (!nuxtApp.isHydrating) return navigateTo(dest, { replace: true })
// First navigation of a freshly opened slider frame: navigate once the app is
// ready, when Nuxt has already restored the initial URL.
onNuxtReady(() => {
void nuxtApp.runWithContext(async () => {
const router = useRouter()
// The user may have navigated away while we waited for an idle moment.
if (!isSamePath(router.currentRoute.value.path, to.path)) return
// `router.replace`, not `navigateTo`: the latter, when it catches another
// navigation in progress, RETURNS a route object instead of navigating —
// and here nobody would apply it.
const failure = await router.replace(dest)
if (failure) console.warn('slider redirect failed', failure.type)
})
})
})
replace: true matters: the page the portal opened is not a step the user took,
and "back" inside the slider should not return to it.
isSamePath has to tolerate a trailing slash. A static server serves /app/
while the router resolves /app, and a strict !== cancels the redirect every
single time.
APP_SID, the portal's session
identifier for this frame. That is deliberate — the target screen needs the
portal's parameters — but it means the value lands in a router history entry and
in route.fullPath. If you send fullPath, the current URL or a navigation
breadcrumb to an analytics or error-reporting service, strip it there. Copy only
the keys you need if your app does not require the rest.Where the navigation is issued decides the outcome. Measured on Nuxt 4.5 with a
statically generated app, frame opened at /app?place=app-options:
onNuxtReady hooks the same app:suspense:resolve, but subscribes later and
defers to requestIdleCallback, so it runs after the restore. There is no other
supported way out: redirectCode is read on the server only, abortNavigation
cannot redirect, and external: true means a full reload of the application.
The slider opens, but shows the main page
One symptom, several unrelated causes, and no error raised by any of them. Check in this order:
- Did the parameter arrive? Log the key names of
$b24.placement.optionsand the value ofplacealone — not the whole object. It can carry the portal's query parameters,APP_SIDamong them, and this repo's own rule is that a credential-shaped value never reaches a logger (see AGENTS.md and thelocal/no-credential-in-loggerlint rule). Log which frame you are in alongside it (window.location.pathname,$b24.placement.placement): both the main window and the slider frame run your code, and in the main windowplaceis legitimately absent — without a frame identifier the main window's perfectly normal "no place" line reads as a slider failure. - Was it read correctly?
PLACEMENT_OPTIONScan arrive as a JSON string;options?.placeon a string isundefined— see placement options. - Did your routing actually run? Log the resulting URL after navigation, not the decision to navigate. A decision that is correct and a navigation that silently did not happen look identical in a log that only records the former. On a prerendered Nuxt route, see the warning above.
- Did the query survive your redirect? If your app also reads
placefrom the frame URL, a redirect that drops the query leaves the target screen unable to tell it is in a slider — and "Cancel" then opens a second copy of the app instead of collapsing the slider.
Steps 2 and 3 reproduce without a portal: serve your built app locally and
open /<your-page>?place=<your-place>, reading place from the query as a
fallback. The routing half of the problem has nothing to do with Bitrix24.
closeSliderAppPage
async closeSliderAppPage(): Promise<void>
Closes the slider with the application.
openPath
async openPath(url: URL, width: number = 1640): Promise<StatusClose>
Opens the specified path inside the portal in a slider.
Handles errors related to mobile device usage and can open the URL in a new tab if the slider is not supported.
Returns StatusClose
This example demonstrates calling the Bitrix24 slider and handling its closing result.
Key points:
- Completion handling: After closing the slider, the SDK returns a status. This allows subsequent operations to be initiated, such as reinitializing application data.
- Limitation: It is virtually impossible to detect the closing of an individual tab using standard JS tools.
- Solution: The
isOpenAtNewWindowparameter in the jsSdk response allows you to determine whether a tab was opened instead of the slider and correctly configure the application's logic.
getUrl
getUrl(path: string = '/'): URL
Returns a URL relative to the domain name and path.
$b24 = await initializeB24Frame()
// ...
const url = $b24.slider.getUrl('/settings/configs/userfield_list.php')
getTargetOrigin
getTargetOrigin(): string
Returns the Bitrix24 address (e.g., https://your_domain.bitrix24.com).