Can data-* attributes be created in Dash?

I would like to have data-* attributes on the elements I create in Dash. (I plan on using BootstrapJS along with Dash, and data-* attributes are preferred to writing more javascript… So I’m not blocked, but I’d like to be sure I’m doing things the best way.)

I’m not sure if this is possible? Looking at dash-html-components/Div.react.js at master · plotly/dash-html-components · GitHub, it seems that every property is listed explicitly, and I haven’t seen anything about creating arbitrary attributes, or data-* attributes in particular.

4 Likes

@mccalluc - This isn’t support right now, but we should support it.

The “issue” is that Dash components are currently generated from a fixed set of properties, the component generation code doesn’t have any support for arbitrary patterns of properties.

To support this, we need to:

  1. Introduce a “special” propType that denotes that this component supports data-* properties. This could either be a special name, like data-*
Div.propTypes = {
     'data-*': PropTypes.string,
     ...
}

or perhaps a special propType that signifies that this is a wildcard attribute, like

Div.propTypes = {
     'data-*': CustomPropTypes.wildcard
     ...
}
  1. Update the HTML component generator with this property: https://github.com/plotly/dash-html-components/blob/6d04a70f098bb8640545467255ae382e8e17cffb/scripts/generate-components.js#L43-L55
  2. Regenerate the HTML components: with $ npm run prepublish https://github.com/plotly/dash-html-components/blob/6d04a70f098bb8640545467255ae382e8e17cffb/package.json#L22
  3. That propType will then be encoded in the metadata.json file that describes all of the properties of all of the components. For example, see the properties of Divhere: https://github.com/plotly/dash-html-components/blob/master/lib/metadata.json#L5465-L5607
  4. Then, we’ll need to update the Dash component generation code to recognize the special attribute name / special attribute type. This will happen in two places:
    • In the base component which does the validation and serialization: https://github.com/plotly/dash/blob/600f532e1230678164479b0f7853f8a9f043e83e/dash/development/base_component.py#L15-L24.
      Validation happens by checking the supplied properties against the valid properties of that component. The list of valid properties are encoded in this self._prop_names list (for example, it might be like ['id', 'children', 'style', 'className', 'src', ...]). data-* properties don’t match that pattern, so we’ll have to have some exception to the logic that’s like:
      if (k not in self._props_names and 
          all([k.startsWith(wildcard_attr) 
                   for wildcard_attr in self._valid_wildcard_attribute_names])):
          raise Exception('Unexpected attribute `{}`...'.format(k))
      
    • Then, we’ll need to make sure that _valid_wildcard_attribute_names is encoded in the dynamic component generation code (https://github.com/plotly/dash/blob/600f532e1230678164479b0f7853f8a9f043e83e/dash/development/base_component.py#L205), something like
      self._valid_wildcard_attribute_names = {list_of_valid_wildcard_attribute_prefixes}
      
      where list_of_valid_wildcard_attribute_prefixes is created by filtering the metadata.json file and looking for either the "wildcard" type that was defined above or the special "data-*" property name.
  5. Add some tests to https://github.com/plotly/dash/blob/600f532e1230678164479b0f7853f8a9f043e83e/tests/development/test_base_component.py and https://github.com/plotly/dash/blob/600f532e1230678164479b0f7853f8a9f043e83e/tests/development/test_component_loader.py

Another thing to consider is how we should deal with the fact that these properties have a hyphen in them. Since they are hyphenated, we can’t do assignments like:

html.Div(data-label='')

however, I believe we could do

html.Div(**{'data-label': ''})

we could do some _ to - replacement too, like:

html.Div(data_label='')

but would introduce some complexity into the BaseComponent. If we do html.Div(**{'data-label': ''}), then we should probably patch the __repr__ in the BaseComponent: https://github.com/plotly/dash/blob/600f532e1230678164479b0f7853f8a9f043e83e/dash/development/base_component.py#L216-L229

1 Like

Thanks! For now, I think I’ll inject the JS I need, but down the road I may need to create new components, and this step-by-step description will be useful.

Is there any conceptual reason why Dash html components should not take arbitrary attributes? Obviously there is the work involved in implementing it, but I’m wondering if there is any objection from a design point of view.

I’m imagining something along the lines of, for example,

html.Div(id="X", className="Y Z", children="Some content",
             keyword_properties={"data-toggle": "collapse", "aria-controls": "collapseExample"})

This is a common pattern in a lot of libraries - a set of recognised arguments, but also the ability to pass on key:value pairs of arbitrary extra arguments, which provides flexibility and future-proofing. Conceptually speaking, HTML takes arbitrary attributes, so it seems to make sense to be able to pass these in. Having a general property dict doesn’t preclude handling specific property patterns like data-* explicitly as well, as and when these arguments are added.

Would this be harder to do than specific properties? Is there some conceptual objection to it?

2 Likes

There is not - it simply has not been implemented yet.

I would love to see this feature implemented. Are there any updates on this topic? Thanks!

1 Like

There are no updates. I have been working on other features and no one from the community has taken a stab at what I outlined above. If you need this prioritized, then your company or organization can sponsor the feature: Consulting, Training & Open-Source Development

1 Like

Update! There is a community PR open to support this feature: https://github.com/plotly/dash/pull/237

5 Likes

You can also solve this (in a slightly hacky way) using the dash_dangerously_set_inner_html package which lets you create components with arbitrary attributes (https://github.com/plotly/dash-dangerously-set-inner-html) an example below as a line in the layout to allow the answer to be a bootstrap collapsable

app_simple.layout = html.Div(children=[
    dash_dangerously_set_inner_html.DangerouslySetInnerHTML('''
    <button class="btn btn-secondary" type="button" data-toggle="collapse" data-target="#collapsableAnswer" aria-expanded="false" aria-controls="collapsableAnswer">
    Show Answer</button>
    '''),
    html.Div(html.Div(html.Div(id='ques_results'), className = 'card card-body'),
             className = 'collapse show', id = 'collapsableAnswer')]
)
1 Like

Looks like this feature is available. Can anyone point me to tutorial to use it. Note I have no experience in Javascript and UI development and hence I am not able to know what this feature is and how it is useful.

1 Like

This isn’t Dash specific, rather it is used for general html/js development: https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes

For example, I’ve used data-alt when writing a JS script that makes it so you can toggle and image to turn into a gif and vis-a-versa: Show and Tell: Creating playable GIFS to document interactive features

I am new to dash and have checked most of the dash forums for using the data-attributes. But could not find any suitable example which explains as to how it can be implemented. Could you please let know if there is any example which can guide me in implementing it.

Also tried using custom scripts but that also doesn’t work
Used this link for reference


Help needed on this !!!

Is this updated, or are there any new information on this ?
Do data-* attributes work somehow with Dash?

If yes, where can I find some information. Thank you.

The syntax is like this:

6 Likes

Another example:

html.Button(
[
html.Span(className=‘navbar-toggler-icon’)
],
className=“navbar-toggler”,
type=‘button’,
**{
‘data-toggle’: ‘collapse’,
‘data-target’: “#navbarNav”,
‘aria-controls’: “navbarNav”,
‘aria-expanded’: “false”,
‘aria-label’: “Toggle navigation”
}
),

2 Likes

Very nice, works great!