Sidebar with icons - expands on hover (and other cool sidebars)

Hey everyone,

I wanted to share a minimal example of a cool side bar that @Sohibjon made. It shows just the icons, but when you hover over the sidebar, it expends to show the description and the link:

sidebar_expand_on_hover

import dash
import dash_bootstrap_components as dbc
from dash import html

app = dash.Dash(
    __name__,
    suppress_callback_exceptions=True,
    external_stylesheets=[dbc.themes.MATERIA, dbc.icons.FONT_AWESOME],
)


sidebar = html.Div(
    [
        html.Div(
            [
                html.H2("Auto ML", style={"color": "white"}),
            ],
            className="sidebar-header",
        ),
        html.Hr(),
        dbc.Nav(
            [
                dbc.NavLink(
                    [html.I(className="fas fa-home me-2"), html.Span("Dashboard")],
                    href="/",
                    active="exact",
                ),
                dbc.NavLink(
                    [
                        html.I(className="fas fa-calendar-alt me-2"),
                        html.Span("Projects"),
                    ],
                    href="/projects",
                    active="exact",
                ),
                dbc.NavLink(
                    [
                        html.I(className="fas fa-envelope-open-text me-2"),
                        html.Span("Datasets"),
                    ],
                    href="/datasets",
                    active="exact",
                ),
            ],
            vertical=True,
            pills=True,
        ),
    ],
    className="sidebar",
)

app.layout = html.Div(
    [
        sidebar,
        html.Div(
            [
                dash.page_container
            ],
            className="content",
        ),
    ]
)

if __name__ == "__main__":
    app.run_server(debug=True)

Put this in a .css file in the assets folder:



/* This creates a skinny side bar fixed to the left of the page */
.sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 5rem;
  padding: 2rem 1rem;
  background-color: #cbd3dd;
  z-index: 1050;
  transition: width 0.1s ease-in-out;
}

/* when the user hovers on the sidebar, expand it */
.sidebar:hover {
  width: 16rem;
}

/* make sure the contents of the navlink don't wrap when navbar collapses */
.sidebar .nav-link {
  width: 100%;
  overflow: hidden;
  white-space: nowrap;
}

/* fix the width of the icons */
.sidebar .nav-link i {
  width: 1rem;
}

/* hide the navlink labels by default */
.sidebar .nav-link span {
  visibility: hidden;
  opacity: 1;
  transition: opacity 0.1s ease-in-out;
}

/* when the sidebar is hovered, reveal the labels */
.sidebar:hover .nav-link span {
  visibility: visible;
  opacity: 1;
  color: black;
}

/* container for the sidebar header. make sure the contents don't wrap when
 * the sidebar is collapsed.
 */
.sidebar-header {
  display: flex;
  justify-content: left;
  align-items: center;
  overflow: hidden;
  white-space: nowrap;
}

/* position the header relative to the logo and hide by default */
.sidebar-header h2 {
  opacity: 0;
  margin-left: 1rem;
  margin-bottom: 0;
  transition: opacity 0.1s ease-in-out;
}

/* reveal the header when the sidebar is toggled */
.sidebar:hover .sidebar-header h2 {
  opacity: 1;
}

/* position the content relative to the collapsed sidebar */
.content {
  margin-left: 7rem;
  margin-right: 2rem;
  padding: 2rem 1rem;
}
14 Likes

Hey hey,
Wanted to add on to @Sohibjon @AnnMarieW awesome work. This example uses Mantine in case anyone is using it. Below is a working example of how to use a media query to make your side nav bar expand and contract at certain breakpoints in a similar fashion to the one above. Mantine has some standard breakpoints you can utilize using Mediaqueries.

This example is using two distinct mediaquery components that show at different breakpoints, an icon only side bar for smaller screens and the full navbar for larger screens.
Peek 2022-09-10 13-06

from dash import html, Dash, dcc
import dash_mantine_components as dmc

app = Dash(__name__,
           external_stylesheets=[
               'https://use.fontawesome.com/releases/v5.8.1/css/all.css'
           ]
           )

app.layout = html.Div([
    dmc.MediaQuery([dmc.Navbar(
        fixed=True,
        width={"base": 250},
        height="100%",
        style={"top": 0},
        children=[
            dmc.Group(
                direction="column",
                grow=True,
                spacing="xl",
                children=[
                    dmc.List(
                        center=True,
                        children=[
                            dmc.ListItem(
                                dcc.Link('Home', href='/'),
                                icon=[
                                    html.I(className='fas fa-home fa-fw fa-lg')],
                                class_name='nav-list-items'),

                            dmc.ListItem(
                                dcc.Link('Data', href='/analytics'),
                                icon=[
                                    html.I(className='fas fa-chart-bar fa-fw fa-lg')],
                                class_name='nav-list-items'),

                            dmc.ListItem(
                                dcc.Link('Map', href='/map'),
                                icon=[
                                    html.I(className='fas fa-map fa-fw fa-lg')],
                                class_name='nav-list-items'),

                            dmc.ListItem(
                                dcc.Link('More Maps',
                                         href='/distro'),
                                icon=[
                                    html.I(className='fas fa-map-marker fa-fw fa-lg')],
                                class_name='nav-list-items'),
                        ])
                ])
        ])], smallerThan="md", styles={'display': 'none'}),
    dmc.MediaQuery([dmc.Navbar(
        fixed=True,
        width={"base": 60},
        height="100%",
        style={"top": 0},
        children=[
            dmc.List(
                center=True,
                children=[
                    dmc.ListItem(
                        dcc.Link(
                            html.I(className='fas fa-home fa-fw fa-lg'), href='/'),
                        class_name='nav-list-items'
                    ),
                    dmc.ListItem(
                        dcc.Link(
                            html.I(className='fas fa-chart-bar fa-fw fa-lg'), href='/'),
                        class_name='nav-list-items'
                    ),
                    dmc.ListItem(
                        dcc.Link(
                            html.I(className='fas fa-map fa-fw fa-lg'), href='/'),
                        class_name='nav-list-items'
                    ),
                    dmc.ListItem(
                        dcc.Link(
                            html.I(className='fas fa-map-marker fa-fw fa-lg'), href='/'),
                        class_name='nav-list-items'
                    )
                ])
        ])], largerThan="md", styles={'display': 'none'})
])

if __name__ == '__main__':
    app.run_server(
        host='0.0.0.0',
        port=8050,
        debug=True,
        dev_tools_props_check=True
    )

Inside your style.css file add:

body, .mantine-Header-root {
    background-color: #f2f4f6 !important;
} 

 .mantine-Navbar-root {
    background-color: #1f2937!important;
}

.mantine-Anchor-root {
    color: #fff!important;
}
.nav-list-items {
    padding: 1rem;
    color: #fff!important;
    text-decoration: none;
    list-style: none;
}

.nav-list-items:hover {
    color: #f2f4f6!important;
    background-color: #374151!important;
}

.mantine-Navbar-root a:-webkit-any-link{
    text-decoration: none;
    color: #f2f4f6 !important;
}

.mantine-Navbar-root ::marker{
    display: none;
}
10 Likes

@tphil10 This looks awesome :star_struck:
Thanks for sharing :slight_smile:

Hi @tphil10,

Thanks for sharing the Mantine example. I do use Mantine components a lot. However, I copied the code you shared and ran the script, it didn’t work like the GIP picture you showed🥲

Do I miss something or anything I should do?

@IvanLiu Hmm well that’s not good. What about it isn’t working? Is it throwing any errors?

Hi @tphil10 ,

Thanks for reply. The code worked fine and it didn’t show any error. However, the layout was so different from yours.:sweat_smile:

It looks like this:

Oh! Haha you are right, my apologies. I updated the css file to include the background color and such for those components. See if that works better.

2 Likes

Hello~

It looks better! Many thanks! Well… :sweat_smile: My sidebar doesn’t expand on hover. Do I miss something?

test

By the way, if I want to add graphs or cards on the right side of the page. Will you suggest create another Div element inside the app layout or shall I use like Container or Grid? Or is there any better way?

Thank you!

@IvanLiu Ah, my bad, realizing the topic header says “expands on hover” lol. My solution expands on window resize, not hover.

As for the container, I created a container that had a margin-left equal to the width of the sidebar.

app.layout = dmc.MantineProvider(
        theme={
            'fontFamily': '"Inter", sans-serif'
        },
        withGlobalStyles=True,
        withNormalizeCSS=True,
        children=[
            dcc.Location(id='url', refresh=False),
            dmc.NotificationsProvider([
                head,
                dmc.MediaQuery([navbar], smallerThan="md", styles={'display': 'none'}),
                dmc.MediaQuery([smaller_navbar], largerThan="md", styles={'display': 'none'}),
                dmc.Container(
                    [dash.page_container],
                    id="page-container",
                    ml="250px",
                    p="1rem",
                    fluid=True
                )
        ], position="top-center")
        ],
)

This is what my full app layout looks like, the dash.page_container is the convention from dash new multipage solution. The margin-left is probably a bit noobish but it works for me. If anyone else has another way of doing it i’d love to know.

2 Likes

Hi @tphil10

Ha, no worries, it’s ok.

Thanks for the snippet of code you provided. Now, I have a better understanding how to arrange my app layout.

Would you please share your web app link or a screenshot? It would be so great to see what it looks like.

Many thanks!

@IvanLiu and @tphil10

I updated the topic head to include “and other cool sidebars”. Thanks for sharing your responsive sidebar @tphil10

If anyone else has nice sidebar examples, please feel free to post it here!

1 Like

Sure thing, my app is https://app.bourbonhuntr.com

1 Like

Hi @AnnMarieW, ok, thank you!

@tphil10 Thanks for sharing. :star_struck:, it’s a great app! I also used my smartphone to open the app, and the layout was still clear, not messy. Awesome!

Is having RWD effect the reason why you used window resized? I also noticed that the sidebar wouldn’t expand if I opened the app via smartphone.

I think this is really cool!!! Is it a card component? Could you please show me how to create one? :pray:

Thank you!

1 Like

Oh, that is cool - Now I think we need to start a Cool Card components topic :sunglasses:

1 Like

Sorry i’m not familiar with the acronym ‘RWD’, what’s that mean? Yea most smartphones have a small viewport so the menu would remain collapsed. You could add more rules into the mediaquery to have it do a variety of things on dozens of different screen sizes.

Hi @tphil10

Ok, I see. I will try and see how it goes. Thank you.

By the way, RWD stands for Responsive Web Design~~

Hi,

First of all, I’d like to thank this amazing community for such great content.
I’m not a coding expert, but I’m trying to replicate the code for the Hover Sidebar and I’m getting a small difference from the original.

After playing around with several things, I discovered that when the MATERIA dbc.themes is applied, everything works fine (Picture 1), but suddenly, when I apply the DARKLY theme, something happens on the icon placement (Picture 2).
My best guess is something with the padding when the Sidebar is collapsed?

It only happens with the DARKLY theme, all the others are ok! :rofl:

image

image

Something I’m missing?
Thanks!

Hi @DenysC and welcome to the Dash community :slightly_smiling_face:

I just wanted you to know that I tried this example with DARKLY and could duplicate the issue. It’s the only theme so far that I can find with the same problem.

There is something in the Darkly that’s interfering with the css for the sidebar. I just haven’t figured out what it is (yet?). Sorry I can’t be more helpful right now.

Here @DenysC , it seems to be something with the padding, adjust this:

/* make sure the contents of the navlink don't wrap when navbar collapses */
.sidebar .nav-link {
  width: 100%;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  display: flex;
  padding-right:1rem;
  padding-left:1rem;
  padding-top:1rem;
}
3 Likes

Hi @AnnMarieW and @jinnyzor,

Jinnyzor solution worked perfectly with the DARKLY theme. I also applied with other themes and all is good now!
Thank you both for the attention and the support.

Denys!

2 Likes