Dash Tour Component

Hi community,

I have been using dash for quite some time (almost from the beginning). I really like the frame work and this weekend I decided to create my own component. Less complicated than I thought and the docs describe the steps really well. I ported reacttour, which will allow you to create your own tour trough your web app.

Note that this is the first time that I programmed in React, and this is thirst time I published anything to the open-source community. The port I made is very simple and does not include all the features yet. However in the upcoming weeks I will update the project and make it more complete.

In the mean time you can download it through pip: pip install dash-tour-component and run the demo

ezgif.com-video-to-gif

import dash_tour_component
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
app = dash.Dash(__name__)


app.layout = html.Div([
	dash_tour_component.DashTour(
		steps=[
			{
				'selector': '[id="my_first_step"]',
				'content': "This is my first step",
				# 'position': "center"
			},
			{
				'selector': '[id="my_second_step"]',
				'content': 'This is my second Step',
			}
		],
		isOpen=False,
		id="tour_component"
	),
	html.Button("Open Tour", id='open_tour_button'),
	html.Div("Test 1", id='my_first_step', style={'text-align': 'center'}),
	html.Div(style={'height': '400px'}),
	html.Div("Test 2", id='my_second_step', style={'text-align': 'center'})
])


@app.callback(
	Output('tour_component', 'isOpen'),
	[Input('open_tour_button', 'n_clicks')],
	prevent_initial_call=True
)
def open_tour_component(value):
	return True


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

Non the less I need the help with the following:

In the steps you pass the content to the tour component. I tried to pass for example a html.Div() instead of a string. As soon as I run the app I get the error that is not a valid argument. I tried several things which did not work. If someone could point me in the correct direction that would be great!

Note, this is how I programmed/defined the steps:

/**
     * The steps in the tour component
     */
    steps: PropTypes.arrayOf(PropTypes.shape({
        'selector': PropTypes.string,
        'content': PropTypes.oneOfType([
            PropTypes.node,
            PropTypes.element,
            PropTypes.func,
        ]).isRequired,
        'position':PropTypes.oneOfType([
            PropTypes.arrayOf(PropTypes.number),
            PropTypes.oneOf(['top', 'right', 'bottom', 'left', 'center']),
        ]),
        'action': PropTypes.func,
        'style': PropTypes.object,
        'stepInteraction': PropTypes.bool,
        'navDotAriaLabel': PropTypes.string,
        })),

Second, is it also possible to pass a function? For example the action needs to be a function, would be awesome if it was possible to pass a python function to update a component!

8 Likes

Looks very nice, thanks for sharing! I’ll try it out for sure.

To my knowledge, at the moment Dash only allows you to pass other components via the children property, i.e. you can’t pass html.Div() as part of the steps property.

Similarly, you can’t pass function handles. Instead, you’ll have to pass something else (e.g. a string), which is then mapped into a function in the JavaScript layer. I have explored a few different possibilities while working on dash-leaflet, and i ended up simply passing the full path to the function as a string. You can see a few more details here,

1 Like

Thansk @Emil to clear this up. I will have a look on how you made dash-leaflet work, nice solution! Either there must be some way to translate it to react? Maybe @chriddyp knows of a workaround/solution?

1 Like

Thanks! The only kind-of-work-around that i know of is to pass object via the children property, as noted in this thread,

However, i would love to know of a better solution. The two issues that you point are (in my opinion) the largest challenges when porting react components to Dash.

1 Like

when I click my_second_step, this component shows up in the middle of screen. can you tell me how to keep this component on the top of screen? Thanks

hi @hspierre,

In my example the first step has the value '[id="my_first_step"]' for the selector key. The id has to correspond with an id in your layout. When this step is activated the modal (or pop up) will move to this location. If it can not find the id it will pop in the middle of the screen. Is this the case? You can also see a warning in the console of your browser, if it can not find the id.

I updated the component -> git link

Most of the props are now available!

4 Likes

Hi, many thanks for this super useful component ! It is great to boost app onboarding.

Do you know if it is possible to use formatting to the content modals ? I have tried using html tags inside the text, using a html.Div or a dcc.Markdown to the content prop but it throws an error.

Did you ever get an answer to this? Running into the issue myself. It’s such a great component, but I need to add some newlines.

I found that creating a custom css class with white-space: pre-line; works

1 Like