ipywidgets icon indicating copy to clipboard operation
ipywidgets copied to clipboard

[ENH] Add ability to specify not only class names, but also ids to newly created widgets

Open rs2 opened this issue 7 years ago • 13 comments
trafficstars

If on needs to manipulate the style or behavior of the widget from the js side, one has to use a class selector, which is suboptimal when having more than one widget of the same kind in the page.

Add e.g. add_id() method just below https://github.com/jupyter-widgets/ipywidgets/blob/master/ipywidgets/widgets/domwidget.py#L20

rs2 avatar Nov 27 '17 11:11 rs2

Thanks for the suggestion. Since we can have more than one view of the same widget on a single page, but you can't have more than one id on a single page, I don't think this will work:

from ipywidgets import IntSlider
from IPython.display import display
w = IntSlider()
display(w)
display(w)

However, you can supply a sufficiently unique class name (say, with a UUID) so that all views of the same widget can be styled/manipulated in a specific way.

jasongrout avatar Nov 27 '17 15:11 jasongrout

What about this:

classname = "mywidget-{0}".format(id(w))
w.add_class(classname)
css_template = """.{{classname}} { ... } """

and then pass css_template to some kind of pre-processor. If the pre-processor is hooked into ipywidgets, it could validate that classname exists, and also adapt its output to the widget's (unstable) internal DOM, etc.

sjdv1982 avatar Dec 23 '17 14:12 sjdv1982

Can you elaborate in your example and give an example of what the ... would look like and how that would be mapped to an example widget's unstable internal DOM? I think that's the crux of the problem, and one that we essentially are tackling with the .style attributes.

jasongrout avatar Jan 02 '18 18:01 jasongrout

It depends on if you want the user to write CSS syntax, or have the styling wrapped in a Python dict from which CSS is auto-generated. Myself, I would much prefer the second. In the context of https://github.com/jupyter-widgets/ipywidgets/issues/577, this is how I would do it:


jupyter_dom_styling = {
    "widget-label": ["font-size", ...],  #or some type information could be added
    "text": ["font-size", ...]    
} 

ipywidgets_internal_dom_mapping = {
    # The internal DOM mapping maps public style values to 
    #   internal style values that reflect the internal widget DOM
    # The example below defines a straightforward 1:1 mapping,
    #  but many-to-one or one-to-many mappings are also possible
    "widget-text": {
        "wlabel": {
            "type": "widget-label",
            "order": 1  #required only if there are multiple widget-labels
            # => DOM class attribute: "widget-label-1-{widget_id}"
        },
        "wtext" {
            "type": "text",
            # => DOM class attribute: "text-{widget_id}"
        },
    }
}

textwidget = ipywidgets.Text()
widget_id = 56789  #unique id, e.g. id(textwidget)

public_style_values = {
    # Provided by the user
    "wlabel": {"font-size": "30px"},
    "wtext": {"font-size": "20px"},
}

internal_style_values = [
    # auto-generated from public style values + widget_text's internal DOM mapping
    {
        "type": "widget-label",
        "order": 1,
        "styling": {"font-size": "30px"}
    },
    {
        "type": "text",
        "styling": {"font-size": "20px"}
    },
]

# CSS is auto-generated from internal_style_values + widget_id
css = """
.widget-label-1-56789 {
    font-size: 30px
}
.text-56789 {
    font-size: 20px
}
"""

This would give the user full control from Python, no TypeScript needed. Control is provided at three levels of abstraction (public style attributes, internal style attributes, and generated CSS). Each level gives more control but is also more fragile.

sjdv1982 avatar Jan 03 '18 13:01 sjdv1982

If I understand your example, you are essentially whitelisting a set of semantic parts in a widget (such as the widget label DOM element), and for each element whitelisting a set of CSS properties that a user can set (such as font-size). The user can then say they want the widget label's font size to be a specific CSS string, and the change is effected. Am I understanding the basic idea behind your proposal correctly?

Do you understand how the current .style system works? It essentially gives you the same benefits (you set whitelisted CSS attributes of whitelisted elements using python syntax), but doesn't require generating CSS or putting it on the page, since it changes the style properties of the DOM elements directly. It also lets you easily share styles between widgets and update them all simultaneously.

jasongrout avatar Jan 04 '18 18:01 jasongrout

On second thought, as mentioned in https://github.com/jupyter-widgets/ipywidgets/issues/577#issuecomment-355368911, I think we should move this proposal and discussion to a different new issue. Your proposal is much broader than the scope of this issue, and deserves its separate issue and discussion (and that will make it easier for future readers to follow the discussion too). @sjdv1982 - would you open a new issue with a summary of your current ideas, and we can carry on the discussion there?

jasongrout avatar Jan 04 '18 19:01 jasongrout

I am not sure. I just wrote down (clearly, I hope?) what seems to me "the obvious way to do it". You core devs are free to agree or disagree.

sjdv1982 avatar Jan 04 '18 20:01 sjdv1982

Thanks. And thanks very much as well for taking the time to type up an extensive example. I don't see what your solution gives us beyond the current .style attribute system (see http://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Styling.html#The-style-attribute for some examples). If my understanding is correct, you are providing a whitelist of a set of widget parts (such as a label), and for each of these, a whitelist of CSS properties to set (such as font size). That's exactly what the current .style system enables us to do.

jasongrout avatar Jan 04 '18 20:01 jasongrout

Maybe there is a misunderstanding then. When I looked at the PR you linked in the other thread, I saw the white-listed properties hard-coded in TypeScript. In my example, they are in a Python dict, for everyone to modify, or bypass via raw CSS. At their own risk of course. Feel free to consider this "an ugly hack" or "the proper way to do it". After all, people disagree about programming.

sjdv1982 avatar Jan 04 '18 20:01 sjdv1982

Ah, so the fundamental difference here is that while the DOM elements are whitelisted and abstracted in both approaches, what you are proposing is allowing any CSS property to be changed for one of the elements, while the .style approach still only whitelists specific CSS properties.

The other difference I see is that the .style approach modifies DOM elements directly, whereas the approach above uses CSS so can be overridden with more specific CSS.

Do I understand it correctly now?

jasongrout avatar Jan 05 '18 16:01 jasongrout

Is there a (easy) way to make a Label boldfont or in color? I know we can make it italicized, e.g.: Label(value=r'\(This\ is\ a\ description\)'), but that seems a bit cumbersome. And how would one allow for "<" and ">" symbols? E.g., how can one display Label('A < B and C > D'), preferably in a color, say, red?

rheiland avatar Jan 31 '19 17:01 rheiland

You can make bold text the same way with bold_label = widgets.Label(r'\(\textbf{bold text}\)') and colored text with blue_label= widgets.Label(value = r'\(\color{blue} {blue \ words}\)') or blue_label2 = widgets.Label(value = r'\(\rm{\color{blue}{reg\ blue\ words}}\)') (for non italicized). I agree that this is a pain and would appreciate basic bold/italicized/color style attributes for label widgets.

twalker309 avatar Mar 15 '19 17:03 twalker309

Following up on https://github.com/jupyterlab/jupyterlab/issues/12252, the (lack of) ability to add names/ids to my HTML elements is becoming a huge hassle since I need to litter my interface with <a name="..."></a> tags so I can select against them in what is quickly becoming a shadow DOM...as JupyterLab decided to nerf any JS communication it would be nice to at least provide a way to add this little bit of help to the HTML the widgets create

b3m2a1 avatar Mar 22 '22 21:03 b3m2a1

I arrived here from #577 which seems to have been closed & locked by bot as resolved, but i believe it is not fully resolved the issue of stylling widgets.

The trouble with locking semi-baked issues is that users can't annotate helpful replies that seem to workaround things.

  • Q: can you unlock the issue?
  • Q: can you explain there what is the current status?

ankostis avatar May 05 '23 12:05 ankostis

Q: can you explain there what is the current status?

For clarity, since it's been several years since we had active discussion on this or the other issue, would you concisely restate the question you're wanting the current status on? Also, what reply on #577 did you find particularly helpful? That discussion took place gradually over a number of years, spanning several iterations of how we do styling in widgets, so it's a bit hard to follow.

jasongrout avatar May 06 '23 03:05 jasongrout

Useful replies:

My Q about the current status not fully addressed in #577 or anywhere: how to style attributes that are not yet officially supported by the style and layout traitlets?

ankostis avatar May 09 '23 09:05 ankostis

  • Q: can you unlock the issue?

I would be in favor of not doing that anymore and unlocking that issue. If community members want to communicate via a particular issue (even when closed), we should not limit that.

maartenbreddels avatar May 09 '23 10:05 maartenbreddels

I would be in favor of not doing that anymore [auto-locking issues]

As a general remark, automation better interfere less with humans and preferably stay in the CI part (particularly now that the AI has crossed the horizon).

ankostis avatar May 09 '23 11:05 ankostis