Apply css_classes to the actual element

When using pn/Button and applying css_classes, the classes are added to the top DIV instead of the actual underlying button element.

This happens in a lot of widgets, and makes it harder to modify css.

Can we apply those classes to the element itself?

@ItamarShDev, one of your other recent questions relates to Jupyter notebooks, but I’m assuming this question is in regards to deploying to the browser with panel serve ?

If you want to change the CSS styling of all buttons, you could consider something like:

import panel as pn
css = '''
button {
    ...
}
'''
pn.config.raw_css.append(css)

If you post your current code and a the resulting html found in your browser’s developer tools window, I could venture a more specific suggestion.

Best,
Charles

Thank you for the reply!

I know that I can directly change css, but that’s not what I am after.

Suppose you have multiple buttons in an application, and you want to modify one button.
You would probably go for:

pn.extension(raw_css = [
"""
.my-class { 
  color: teal; 
  background-color: black;
}
"""])

...
button = pn.widgets.Button(...., css_classes=['new-class'])
...

But, the css class is added to a grandparent of said button.
see:

This makes handling the custom classes harder.
The current css would have no affect.
And now I need to know where the class is applied.
something like:
.my-class button {
color: teal;
background-color: black;
}

this is too specific and beats the purpose of having the ability to add custom classes

Making a general class can be very tedious, and applying the class to the direct widget would help a lot.

4 Likes

@ItamarShDev, Thanks for the additional details.

Here’s an idea. In addition to creating new classes, pn.config.raw_css can also override existing classes.

Panel provides five built-in button styles, each of which is styled with a distinct (and override-able) CSS class.

For example, a 'primary' and 'warning' button would normally render like this:

But if I override the .bk-btn-warning class as follows…

css = '''
.bk-root .bk-btn-warning {
    color: teal; 
    background-color: black;
}
'''
pn.config.raw_css.append(css)

… then I can force a stylistic change to the 'warning' button without affecting the 'primary' button:

This doesn’t unlock infinite possibility, but it does give you the option of five distinct custom buttons styles. (One for each of the five built-in classes.)

Does this help address your use-case? Or am I missing something? I’ll be curious to know either way, and can try to come up with some more solutions if this does not suffice.

Best,
Charles

1 Like

Thank you

I actually already do that.

My question because I have some Buttons that should look a bit different than others.

I will stick to the specific class per widget.

But I still think this issue should be addressed in some way or another because this makes css_classes a bit confusing to use

4 Likes

I agree with @ItamarShDev. I am trying to apply class specific styling and nothing is working!

Specifically i’m trying to do this with tabulator. As I want one of my column headers to have vertical labels, but only for one table not all of them.

For example. This Works:

import pandas as pd
import panel as pn

# Ensure Panel extension is loaded
pn.extension('tabulator')

# Example DataFrame
data = {'Column1': [1, 2, 3], 'Column2': [4, 5, 6], 'Column3': [7, 8, 9]}
df = pd.DataFrame(data)

# Define widths for numeric columns (as an example)
numeric_widths = {'Column1': 100, 'Column2': 150, 'Column3': 200}

# Define Tabulator widget with a unique theme class
tabulator = pn.widgets.Tabulator(
    df,
    widths=numeric_widths,
    theme='simple',
)

# Define Custom CSS to Rotate Column Headers for the specific class
css = """
.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title {
    transform: rotate(-45deg);
    transform-origin: center;
    text-align: left;
    vertical-align: middle;
}
"""

# Apply custom CSS to Panel's Tabulator
pn.config.raw_css.append(css)

# Display the Tabulator
tabulator.servable()

But this doesn’t:

import pandas as pd
import panel as pn

# Ensure Panel extension is loaded
pn.extension('tabulator')

# Example DataFrame
data = {'Column1': [1, 2, 3], 'Column2': [4, 5, 6], 'Column3': [7, 8, 9]}
df = pd.DataFrame(data)

# Define widths for numeric columns (as an example)
numeric_widths = {'Column1': 100, 'Column2': 150, 'Column3': 200}

# Define Tabulator widget with a unique theme class
tabulator = pn.widgets.Tabulator(
    df,
    widths=numeric_widths,
    theme='simple',
    css_classes=['rotated-headers'],
)

# Define Custom CSS to Rotate Column Headers for the specific class
css = """
.rotated-headers .tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title {
    transform: rotate(-45deg);
    transform-origin: center;
    text-align: left;
    vertical-align: middle;
}
"""

# Apply custom CSS to Panel's Tabulator
pn.config.raw_css.append(css)

# Display the Tabulator
tabulator.servable()

Oh I was able to resolve my above issue by using panel stylesheets (new in 1.0). Documented here: Apply CSS — Panel v1.3.1

The following works for me:

import pandas as pd
import panel as pn

# Ensure Panel extension is loaded
pn.extension('tabulator')

# Example DataFrame
data = {'Column1': [1, 2, 3], 'Column2': [4, 5, 6], 'Column3': [7, 8, 9]}
df = pd.DataFrame(data)

# Define widths for numeric columns (as an example)
numeric_widths = {'Column1': 100, 'Column2': 150, 'Column3': 200}

# Define Custom CSS to Rotate Column Headers for the specific class
css = """
.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title {
    transform: rotate(-45deg);
    transform-origin: center;
    text-align: left;
    vertical-align: middle;
}
"""
# Define Tabulator widget with a unique theme class
tabulator = pn.widgets.Tabulator(
    df,
    widths=numeric_widths,
    stylesheets=[css],
)

# Display the Tabulator
tabulator.servable()
1 Like