Can't get Bootstrap Carousel to work (with external scripts)

I’m trying to use Bootstrap’s Carousel element because the component from dbc doesn’t support anything but images, and I want a carousel for dcc.Graph components. So to start off, I tried making a minimal example using the official bootstrap carousel example as a guide… but it doesn’t work (the contents don’t “carouse”), and I don’t know why. Here is the code:

import dash
from dash import html

external_scripts = [
    {
        "src": "https://code.jquery.com/jquery-3.3.1.slim.min.js",
        "integrity": "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo",
        "crossorigin": "anonymous",
    },
    {
        "src": "https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.min.js",
        "integrity": "sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM",
        "crossorigin": "anonymous",
    },
]

external_stylesheets = [
    {
        "href": "https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css",
        "rel": "stylesheet",
        "integrity": "sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T",
        "crossorigin": "anonymous",
    }
]

app = dash.Dash(
    __name__,
    external_scripts=external_scripts,
    external_stylesheets=external_stylesheets,
)

app.layout = html.Div(
    [
        html.Div(
            id="carouselExampleSlidesOnly",
            className="carousel slide",
            **{"data-ride": "carousel"},
            children=[
                html.Div(
                    className="carousel-inner",
                    children=[
                        html.Div(
                            className="carousel-item active",
                            children=[html.P("one")],
                        ),
                        html.Div(
                            className="carousel-item",
                            children=[html.P("two")],
                        ),
                        html.Div(
                            className="carousel-item",
                            children=[html.P("three")],
                        ),
                    ],
                )
            ],
        )
    ]
)

if __name__ == "__main__":
    app.run_server(debug=True)

What is interesting, is that if you check the browsers inspect tool, then everything needed seems to be in place. After removing all dash related addons, the remaining html works as expected, as can be seen here on jsfiddle:
https://jsfiddle.net/rhgb9cjp/

Any help would be much appreciated, as I’ve also tried using Carousel from dash_trich_components, but it is extremely buggy and no longer maintained. I’m almost at the point I regret not just making my entire project in raw html/css/js.
P.s. I’m not a very advanced web developer, so if I’m missing something obvious here, my bad. I spent an entire day on this, and can’t seem to find what’s wrong

HI @mayushii21 welcome to the forums.

If the carousel is the only content of your app, you could emulate this, I think this thread might be helpful:

1 Like

Thank you for the response, but the carousel is only a small part of my app, and though the thread does partially achieve what I was looking for, it does not solve the problem as to why using external javascript doesn’t work. It seems extreemly overly complicated to go through building a carousel with dash components and complicated callbacks, when multiple existing solutions already exist in javascript. What if I wanted something more advanced, like a 3d circular carousel? The solution can easily be found in js, but I can’t even begin to imagin how to impliment it in raw dash… That said, I’m more of a beginner than anything. The response just above yours in that thread is pretty much what I want, as I don’t need buttons, just an automatic carousel. But I also want the carousel to auto pause when someone hovers a mouse above it, and I want it to have slideshow like transitions (slide to the left, instead of just replace), yet I can’t seem to figure out how to do that. In the meantime, react-slick, as well as other js implementations exist and do exactly what I want. So basically, I would really like to figure out how to properly incorporate javasctipt into my dash app and understand what it is I’m doing wrong. Big thanks for sharing that thread! I wouldn’t’ve found it with that name :sweat_smile:

Hello @mayushii21,

Welcome to the community!

When I run your example… it works exactly as designed…

Cool find, btw.

What version of Dash are you running?

@jinnyzor when you run the dash example it works the same as jsfiddle? I just updated to the latest Dash - 2.14.0, and nothing happens… it just shows “one” and that’s it, no changes

Correct. It works just as in your example.

Make sure your mouse isnt over the div accidentally. XD

Also, check for console errors

huh… interesting and strange :thinking: I get no errors, and my mouse isn’t even on my brouser… Tried different browsers btw, and it doesn’t work for me… I even tried messing with app.index_string and no change… I don’t get it

Try dropping dash to 2.12, I am running on 2.10.2

nope, just created a clean environment and installed 2.10.2 and it doesn’t work for me…

What version of Flask do you have?

flask version is 2.2.5 - the default that got installed when installing dash. Before I had 2.2.2, didn’t work then either

What does your head look like?

Something like this, if this is what you mean:
image

a total of 100k+ characters, so I can’t paste the whole thing here

@jinnyzor I tried deploying it to https://mayushii.pythonanywhere.com/ just to check maybe it’s something with how my pc+browser works, but… this doesn’t work either, nor does it work on my phone. Could you check if this works for you?

I think it has to do with the timing of when the script runs.

Open your link in a new tab, do not view it until it is completely loaded, and then navigate to it.

I just tried, and it doesn’t work :confused:

Try this:

import dash
from dash import html, Output, Input

external_scripts = [
    {
        "src": "https://code.jquery.com/jquery-3.3.1.slim.min.js",
        "integrity": "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo",
        "crossorigin": "anonymous",
    },
    {
        "src": "https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.min.js",
        "integrity": "sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM",
        "crossorigin": "anonymous",
    },
]

external_stylesheets = [
    {
        "href": "https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css",
        "rel": "stylesheet",
        "integrity": "sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T",
        "crossorigin": "anonymous",
    }
]

app = dash.Dash(
    __name__,
    external_scripts=external_scripts,
    external_stylesheets=external_stylesheets,
)

app.layout = html.Div(
    [
        html.Div(
            id="carouselExampleSlidesOnly",
            className="carousel slide",
            **{"data-ride": "carousel"},
            children=[
                html.Div(
                    className="carousel-inner",
                    children=[
                        html.Div(
                            className="carousel-item active",
                            children=[html.P("one")],
                        ),
                        html.Div(
                            className="carousel-item",
                            children=[html.P("two")],
                        ),
                        html.Div(
                            className="carousel-item",
                            children=[html.P("three")],
                        ),
                    ],
                )
            ],
        )
    ]
)

app.clientside_callback(
    """function () {
        var ClassName$2 = {
    CAROUSEL: 'carousel',
    ACTIVE: 'active',
    SLIDE: 'slide',
    RIGHT: 'carousel-item-right',
    LEFT: 'carousel-item-left',
    NEXT: 'carousel-item-next',
    PREV: 'carousel-item-prev',
    ITEM: 'carousel-item',
    POINTER_EVENT: 'pointer-event'
  };
  var Selector$2 = {
    ACTIVE: '.active',
    ACTIVE_ITEM: '.active.carousel-item',
    ITEM: '.carousel-item',
    ITEM_IMG: '.carousel-item img',
    NEXT_PREV: '.carousel-item-next, .carousel-item-prev',
    INDICATORS: '.carousel-indicators',
    DATA_SLIDE: '[data-slide], [data-slide-to]',
    DATA_RIDE: '[data-ride="carousel"]'
  };
  var Carousel = window.bootstrap.Carousel
var carousels = [].slice.call(document.querySelectorAll(Selector$2.DATA_RIDE));

    for (var i = 0, len = carousels.length; i < len; i++) {
      var $carousel = $(carousels[i]);

      Carousel._jQueryInterface.call($carousel, $carousel.data());}
        return window.dash_clientside.no_update
    }""",
    Output('carouselExampleSlidesOnly', 'id'),
    Input('carouselExampleSlidesOnly', 'id')
)

if __name__ == "__main__":
    app.run_server(debug=True)

Check out Bootstrap’s recommended way to apply here:


OLD

And here is the cleaner version since we know what you want to spin up:

import dash
from dash import html, Output, Input

external_scripts = [
    {
        "src": "https://code.jquery.com/jquery-3.3.1.slim.min.js",
        "integrity": "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo",
        "crossorigin": "anonymous",
    },
    {
        "src": "https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.min.js",
        "integrity": "sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM",
        "crossorigin": "anonymous",
    },
]

external_stylesheets = [
    {
        "href": "https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css",
        "rel": "stylesheet",
        "integrity": "sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T",
        "crossorigin": "anonymous",
    }
]

app = dash.Dash(
    __name__,
    external_scripts=external_scripts,
    external_stylesheets=external_stylesheets,
)

app.layout = html.Div(
    [
        html.Div(
            id="carouselExampleSlidesOnly",
            className="carousel slide",
            **{"data-ride": "carousel"},
            children=[
                html.Div(
                    className="carousel-inner",
                    children=[
                        html.Div(
                            className="carousel-item active",
                            children=[html.P("one")],
                        ),
                        html.Div(
                            className="carousel-item",
                            children=[html.P("two")],
                        ),
                        html.Div(
                            className="carousel-item",
                            children=[html.P("three")],
                        ),
                    ],
                )
            ],
        )
    ]
)

app.clientside_callback(
    """function (id) {
        var $carousel = $(`#${id}`)
        var Carousel = window.bootstrap.Carousel
        Carousel._jQueryInterface.call($carousel, $carousel.data());
        return window.dash_clientside.no_update
    }""",
    Output('carouselExampleSlidesOnly', 'id'),
    Input('carouselExampleSlidesOnly', 'id')
)

if __name__ == "__main__":
    app.run_server(debug=True)

it works! But how come it doesn’t work without the callback? Is that a bug that will be fixed, or is that just how dash works?

Its a flaw feature in bootstrap’s code, it is assuming that when you add the script and the webpage that everything is already loaded to the DOM tree. it loops through the DOM tree and auto applies carousel to any that match what it is looking for.

This is not the case for Dash, as the original layout is only available at the time that bootstrap goes through the DOM tree. I just found the function that bootstrap was calling when the script was added and retriggered it once the element was fully rendered by Dash.

Check out the order in which the elements are requested in the Network tab:

1 Like