Ipywidgets: Individual widget styling

Created on 12 Aug 2016  路  25Comments  路  Source: jupyter-widgets/ipywidgets

After #272 there seems to be no way to change the css properties of an individual widget. While it doesn't make sense to have a global exposure, each individual widget should have specific traits that can be set or changed

@jasongrout

feature request resolved-locked

Most helpful comment

@dmadeka as a work around use .add_class(...) to add a unique class to the individual widget you want to style, then use the IPython HTML class to display some CSS that changes the style of that class.

All 25 comments

This is something that we have decided to remove for now because we don't want to expose the specifics of the DOM structure the widgets which would effectively become part of the public API as soon as we allow css customization.

Wait, so how does each widget having individual styling attributes expose the DOM Structure?

It does not! What does is exposing something like set_css. Ensuring that a set_css call will behave in the same way in the future implied not changing the DOM structure.

Regarding the styling of widgets with attributes, it is difficult to draw the line.

At the moment, we expose layout-related css properties of the top-level DOM element to let the user define his widget layout.

But the styling of the leaf content (e.g. a slider with description, slider, handler, readout) is not done easily in a systematic way, or at least we have not yet figured out a good way to decide what should be customizable and what not. - so that is why we removed it completely _for now_...

Okay, so no room for temporary widget level traits to control specific things?

Or must I add_class and then use %css?

I think that the button case is simple enough that we can probably agree on some top-level properties (or decide on how o regroup them in a style attribute like for layout)

I just don't know if we should have one such style object per div of the core ipywidgets widgets or a namespaced single object with a bunch of properties (handle_color, readout_fontsize etc)

Ping @jdfreder .

@dmadeka as a work around use .add_class(...) to add a unique class to the individual widget you want to style, then use the IPython HTML class to display some CSS that changes the style of that class.

@jdfreder Thats not the prettiest thing, imagine if we had a vector of N text boxes which we coded by color and connected to another widget by that same color. We'd need a class for each one and then to trigger CSS on each one. Is there any hope for patch traits like color and background color in the most used ones?

@dmadeka I agree, but color may apply to different things in a widget (slider handle, rail, description...) So that is why we decided to reduce the API surface for now. But this thread is probably the right place to start making proposals of what a general approach might look like.

Proposal: A base WidgetStyle class which is a widget like Layout, specialized for each widget type exposing higher level abstractions than css. For the SliderStyle object:

  • handle color
  • slider color
  • readout color

we could limit this to colors at first...

Besides, I would like to tackle the question of default values for layout (which is '') so that the value from the css stylesheet is used, reflecting the "natural size".

Another possible complication (that we probably don't want to tackle at the moment) - taking into account theming on the browser side: perhaps the handle color should be on color in a dark theme, another in a light theme.

@jdfreder The issue with that is imagine if we have some notebook css in ~/.jupyter/custom/custom.css

That creates multiple issues with the widgets, so you might need to set the individual widget styles as important or make them arbitrarily specific

I agree that the issue is important, but rollback of this capability was intentional, because the old API was unsustainable. Happy to welcome a solution, as long as it's stateful and one-size fits all. We've had problems finding a solution that can check both of those boxes off.

Just to see if I understand this correctly. If I have a TextWidget and I like to change the color of the background of this widget, during run time, this is not easily possible? At least

from ipywidgets import Text

text = Text(
    description = "Test",
    value = "Text",
)
text.background_color = "red"

display(text)

Will not have a red background. Even though the text.background_color is an available attribute of text.

This has been implemented already in master.

For reference, the infrastructure was merged in https://github.com/ipython/ipywidgets/pull/1070

Proposal: A base WidgetStyle class which is a widget like Layout, specialized for each widget type exposing higher level abstractions than css. For the SliderStyle object:

handle color
slider color
readout color
we could limit this to colors at first...

Does not seem to work yet (ipywidgets.__version__ = 7.0.0). I can only set the handle color.
As I am working with a dark background style the default black readout color is very annoying...
Or am I doing something wrong:

layout = {'width':'90%', 'height': '80px', 'border': 'solid', 'fontcolor':'red'}
style = {'handle_color': 'red', 'readout_color': 'red', 'slider_color': 'red'}
slides = widgets.interactive(lambda m, f: run(axes, lines, q, p, E, m, twopi*f, dt),
                            f=FloatSlider(min=1, max=100, step=1, continuous_update=False, layout=layout, style=style),
                            m=FloatSlider(min=1, max=100, step=1, continuous_update=False, layout=layout, style=style))

Handle color and description width is the only thing implemented right now for the slider. We thought we'd start conservative.

The description labels and all of the other text probably gives you issues too, right?

If you have a dark background, it may be better to change the text color across all of ipywidgets (as part of a theme change), rather than just on a single widget.

@jasongrout

If you have a dark background, it may be better to change the text color across all of ipywidgets (as part of a theme change), rather than just on a single widget.

Hello, how is possible to change the theme of all the ipywidgets? Thank you!

If you really need dark buttons with white text, you can abuse the default styles with the following (you may sub info for warning or danger, all three give white font):

button = ipywidgets.Button(description='wow', button_style='info')
button.style.button_color = '#1e1e1e'

Hello, how is possible to change the theme of all the ipywidgets? Thank you!

In JupyterLab (which is designed to be themed), the ipywidgets theme variables you can set in your theme are:

https://github.com/jupyter-widgets/ipywidgets/blob/master/packages/controls/css/widgets-base.css#L14-L53

As you can see, we get the font color straight from the JupyterLab theme. So change the color in the jlab theme, and it automatically changes for all widgets.

For the classic notebook, which is not designed for easy theming, we have to compile down to specific colors for backwards compatibility, so it's much more difficult (i.e., you would have to distribute your own widgets package with your own compiled css, or you would have to find all places fonts were used and insert appropriate css on the page).

Was this page helpful?
0 / 5 - 0 ratings