# Styling & Appearance | NiceGUI

[Button: icon:menu]

[](/)

[Installation](/#installation)

[Features](/#features)

[Demos](/#demos)

[Documentation](/documentation)

[Examples](/examples)

[Why?](/#why)

[Button]

[Button]

[](https://github.com/zauberzeug/nicegui/)

[Button: icon:more_vert]

# Styling & Appearance

## Styling

NiceGUI uses the [Quasar Framework](https://quasar.dev/) and hence has its full design power.
Each NiceGUI element provides a `props` method whose content is passed [to the Quasar component](https://justpy.io/quasar_tutorial/introduction/#props-of-quasar-components):
Have a look at [the Quasar documentation](https://quasar.dev/vue-components/button#design) for all styling props.
Props with a leading `:` can contain JavaScript expressions that are evaluated on the client.
You can also apply [Tailwind CSS](https://tailwindcss.com/) utility classes with the `classes` method.

If you really need to apply CSS, you can use the `style` method. Here the delimiter is `;` instead of a blank space.

All three functions also provide `remove` and `replace` parameters in case the predefined look is not wanted in a particular styling.

main.py

[Button]

````python
from nicegui import ui

ui.radio(['x', 'y', 'z'], value='x').props('inline color=green')
ui.button(icon='touch_app').props('outline round').classes('shadow-lg')
ui.label('Stylish!').style('color: #6E93D6; font-size: 200%; font-weight: 300')

ui.run()
````

## Try styling NiceGUI elements!


    Try out how
    [Tailwind CSS classes](https://tailwindcss.com/),
    [Quasar props](https://justpy.io/quasar_tutorial/introduction/#props-of-quasar-components),
    and CSS styles affect NiceGUI elements.


Select an element from those available and start styling it!

ui.button

main.py


                        ```py
                        from nicegui import ui

                        element = ui.button('element')
                        ```
                    

`element.classes('`

`')`

`element.props('`

`')`

`element.style('`

`')`


                        ```py
                        ui.run()
                        ```
                    


    **How to overrule Quasar with Tailwind classes or plain CSS**

    Some Quasar classes (e.g. `bg-primary`) are marked as `!important` and, thus, would even overrule `!important` Tailwind classes.
    At NiceGUI, we deviate from Quasar's design by moving Quasar's `!important` styles to a less powerful CSS layer.
    While still important enough to ensure Quasar works as expected, you can now overrule Quasar for more customization.

    Try out class `!bg-red-500` on a `ui.button` to see important Tailwind classes overruling Quasar.
    Similarly, you can set the style `background-color:red !important` to achieve the same effect.


## CSS Layers

NiceGUI defines the following CSS layers (in order of increasing priority):
"theme", "base", "quasar", "nicegui", "components", "utilities", "overrides", and "quasar_importants".

You don't need to put your custom CSS into layers for basic styling.
However, to override Quasar's `!important` rules, you should define your CSS in an appropriate layer:
use "components" for component-specific styles or "utilities" for utility classes,
depending on the purpose of your custom styles.
Note that you need to use `!important` in your custom styles
because Quasar defines most of its CSS with `!important`,
which would otherwise take precedence.

In the example below, we override a button's background color using the "utilities" layer.

*Updated in NiceGUI 3.0.0: CSS layers have been introduced.*

main.py

[Button]

````python
from nicegui import ui

ui.add_css('''
    @layer utilities {
       .red-background {
           background-color: red !important;
        }
    }
''')
ui.button('Red Button').classes('red-background')

ui.run()
````

## Tailwind CSS Layers

Tailwind CSS' `@layer` directive allows you to define custom classes that can be used in your HTML.
NiceGUI supports this feature by allowing you to add custom classes to the `components` layer.
This way, you can define your own classes and use them in your UI elements.
In the example below, we define a custom class `blue-box` and apply it to two labels.
Note that the style tag is of type `text/tailwindcss` and not `text/css`.

Also note: This requires the default Tailwind CSS engine (not UnoCSS).

main.py

[Button]

````python
from nicegui import ui

ui.add_head_html('''
    <style type="text/tailwindcss">
        @layer components {
            .blue-box {
                @apply bg-blue-500 p-12 text-center shadow-lg rounded-lg text-white;
            }
        }
    </style>
''')

with ui.row():
    ui.label('Hello').classes('blue-box')
    ui.label('world').classes('blue-box')

ui.run()
````

## UnoCSS engine

As an alternative to using the [Tailwind CSS Play CDN engine](https://v3.tailwindcss.com/docs/installation/play-cdn),
you can also use the [UnoCSS engine](https://unocss.dev/) to let Tailwind CSS classes take effect.

Pass one of the following presets to `ui.run(unocss=...)`:

- "mini": [UnoCSS Mini preset](https://unocss.dev/presets/mini)
- "wind3": [UnoCSS Wind3 preset](https://unocss.dev/presets/wind3)
- "wind4": [UnoCSS Wind4 preset](https://unocss.dev/presets/wind4)

UnoCSS is a smaller library and more performant, especially on small pages.
In Lighthouse Desktop, load time for this page went from 1.1s down to 0.7s.

However, full compatibility with Tailwind CSS is not guaranteed.
For example, Tailwind CSS Layers (see above) do not work with UnoCSS.

*Added in NiceGUI 3.7.0*

main.py

[Button]

````python
from nicegui import ui

label = ui.label('This label becomes red dynamically.')

ui.button('Become red', on_click=lambda: ui.run_javascript(f'''
    {label.html_id}.classList.add("text-red-500")
'''))

ui.run(unocss='mini')
````

## [ElementFilter](/documentation/element_filter)

Sometimes it is handy to search the Python element tree of the current page.
``ElementFilter()`` allows powerful filtering by kind of elements, markers and content.
It also provides a fluent interface to apply more filters like excluding elements or filtering for elements within a specific parent.
The filter can be used as an iterator to iterate over the found elements and is always applied while iterating and not when being instantiated.

And element is yielded if it matches all of the following conditions:

- The element is of the specified kind (if specified).
- The element is none of the excluded kinds.
- The element has all of the specified markers.
- The element has none of the excluded markers.
- The element contains all of the specified content.
- The element contains none of the excluded content.

- Its ancestors include all of the specified instances defined via ``within``.
- Its ancestors include none of the specified instances defined via ``not_within``.
- Its ancestors include all of the specified kinds defined via ``within``.
- Its ancestors include none of the specified kinds defined via ``not_within``.
- Its ancestors include all of the specified markers defined via ``within``.
- Its ancestors include none of the specified markers defined via ``not_within``.

Element "content" includes its text, label, icon, placeholder, value, message, content, source.
Partial matches like "Hello" in "Hello World!" are sufficient for content filtering.

:kind: filter by element type; the iterator will be of type ``kind``
:marker: filter by element markers; can be a list of strings or a single string where markers are separated by whitespace
:content: filter for elements which contain ``content`` in one of their content attributes like ``.text``, ``.value``, ``.source``, ...; can be a single string or a list of strings which all must match
:local_scope: if ``True``, only elements within the current scope are returned; by default the whole page is searched (this default behavior can be changed with ``ElementFilter.DEFAULT_LOCAL_SCOPE = True``)
:only_visible: if ``True``, filter out elements that are not visible or whose ancestors are not visible

main.py

[Button]

````python
from nicegui import ElementFilter, ui

with ui.card():
    ui.button('button A')
    ui.label('label A')

with ui.card().mark('important'):
    ui.button('button B')
    ui.label('label B')

ElementFilter(kind=ui.label).within(marker='important').classes('text-xl')

ui.run()
````

[See more →](/documentation/element_filter)

## [Query Selector](/documentation/query)

To manipulate elements like the document body, you can use the `ui.query` function.
With the query result you can add classes, styles, and attributes like with every other UI element.
This can be useful for example to change the background color of the page (e.g. `ui.query('body').classes('bg-green')`).

:selector: the CSS selector (e.g. "body", "#my-id", ".my-class", "div > p")

main.py

[Button]

````python
from nicegui import ui

def set_background(color: str) -> None:
    ui.query('body').style(f'background-color: {color}')

ui.button('Blue', on_click=lambda: set_background('#ddeeff'))
ui.button('Orange', on_click=lambda: set_background('#ffeedd'))

ui.run()
````

[See more →](/documentation/query)

## [Color Theming](/documentation/colors)

Sets the main colors (primary, secondary, accent, ...) used by `Quasar <https://quasar.dev/style/theme-builder>`_ on a per-page basis.

Note: This takes precedence over the global color configuration set via ``app.colors()``.

:primary: Primary color (default: "#5898d4")
:secondary: Secondary color (default: "#26a69a")
:accent: Accent color (default: "#9c27b0")
:dark: Dark color (default: "#1d1d1d")
:dark_page: Dark page color (default: "#121212")
:positive: Positive color (default: "#21ba45")
:negative: Negative color (default: "#c10015")
:info: Info color (default: "#31ccec")
:warning: Warning color (default: "#f2c037")
:custom_colors: Custom color definitions for branding (needs ``ui.colors`` to be called before custom color is ever used, *added in version 2.2.0*)

main.py

[Button]

````python
from nicegui import ui

ui.button('Default', on_click=lambda: ui.colors())
ui.button('Gray', on_click=lambda: ui.colors(primary='#555'))

ui.run()
````

[See more →](/documentation/colors)

## CSS Variables

You can customize the appearance of NiceGUI by setting CSS variables.
Currently, the following variables with their default values are available:

- `--nicegui-default-padding: 1rem`
- `--nicegui-default-gap: 1rem`


main.py

[Button]

````python
from nicegui import ui

ui.add_css('''
    :root {
        --nicegui-default-padding: 0.5rem;
        --nicegui-default-gap: 3rem;
    }
''')
with ui.card():
    ui.label('small padding')
    ui.label('large gap')

ui.run()
````

## Overwrite Tailwind's Default Style

Tailwind CSS resets the default style of HTML elements, like the font size of `h2` elements in this example.
You can overwrite these defaults by adding a style tag with type `text/tailwindcss`.
Without this type, the style will be evaluated too early and will be overwritten by Tailwind.

main.py

[Button]

````python
from nicegui import ui

ui.add_head_html('''
    <style type="text/tailwindcss">
        h2 {
            font-size: 150%;
        }
    </style>
''')
ui.html('<h2>Hello world!</h2>', sanitize=False)

ui.run()
````

## [Dark mode](/documentation/dark_mode)

You can use this element to enable, disable or toggle dark mode on the page.
The value `None` represents auto mode, which uses the client's system preference.

Note that this element overrides the `dark` parameter of the `ui.run` function and page decorators.

:value: Whether dark mode is enabled. If None, dark mode is set to auto.
:on_change: Callback that is invoked when the value changes.

main.py

[Button]

````python
from nicegui import ui

dark = ui.dark_mode()
ui.label('Switch mode:')
ui.button('Dark', on_click=dark.enable)
ui.button('Light', on_click=dark.disable)

ui.run()
````

[See more →](/documentation/dark_mode)

## [Add CSS style definitions to the page](/documentation/add_style)

This function can be used to add CSS style definitions to the head of the HTML page.

*Added in version 2.0.0*

:content: CSS content (string or file path)
:shared: whether to add the code to all pages (default: ``False``, *added in version 2.14.0*)

main.py

[Button]

````python
from nicegui import ui

ui.add_css('''
    .red {
        color: red;
    }
''')
ui.label('This is red with CSS.').classes('red')

ui.run()
````

[See more →](/documentation/add_style)

## Using other Vue UI frameworks

**This is an experimental feature.**
**Many NiceGUI elements are likely to break, and the API is subject to change.**

NiceGUI uses the [Quasar Framework](https://quasar.dev/) by default.
However, you can also try to use other Vue UI frameworks
like [Element Plus](https://element-plus.org/en-US/) or [Vuetify](https://vuetifyjs.com/en/).
To do so, you need to add the framework's JavaScript and CSS file to the head of your HTML document
and configure NiceGUI accordingly by extending or replacing `app.config.vue_config_script`.

*Added in NiceGUI 2.21.0*

main.py

[Button]

````python
from nicegui import app, ui

ui.add_body_html('''
    <link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css" />
    <script defer src="https://unpkg.com/element-plus"></script>
''')
app.config.vue_config_script += '''
    app.use(ElementPlus);
'''

with ui.element('el-button').on('click', lambda: ui.notify('Hi!')):
    ui.html('Element Plus button', sanitize=False)

ui.button('Quasar button', on_click=lambda: ui.notify('Ho!'))

ui.run()
````

**Nice**GUI

The Python UI framework that shows up in your browser.

[](https://github.com/zauberzeug/nicegui/)

[](https://discord.gg/TEpFeAaF4f)

[](https://www.reddit.com/r/nicegui/)

Resources

[Documentation](/documentation)

[Examples](/examples)

[LLM reference](/llms.txt)

[GitHub](https://github.com/zauberzeug/nicegui/)

[PyPI](https://pypi.org/project/nicegui/)

Community

[Discussions](https://github.com/zauberzeug/nicegui/discussions)

[Discord](https://discord.gg/TEpFeAaF4f)

[Reddit](https://www.reddit.com/r/nicegui/)

[Contributing](https://github.com/zauberzeug/nicegui/blob/main/CONTRIBUTING.md)

[Sponsors](https://github.com/sponsors/zauberzeug)

Legal

[Imprint](/imprint_privacy#imprint)

[Privacy](/imprint_privacy#privacy)

Made with NiceGUI by [Zauberzeug](https://zauberzeug.com)

© 2026 [Zauberzeug GmbH](https://zauberzeug.com)