CSS Question: how to style html.A as a button?

Hello, all. In my app I have a download button that I made using a html.Button within a html.A component, but no matter what I do, I cannot figure out how get the resulting button to inherit the look of the other buttons within the html.Div they are all under.

To structure and neatly organize all of my components, I use css-grid-layout (mozilla has a good intro), and a nice side-effect of using it in a Div is that all the html.Button's placed within it gain a rectangular sharp look. I would like to figure out how to get my download link to also inherit this look. Would anyone care to lend me any advice on this?

MWE:

import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html


app = dash.Dash(dev_tools_hot_reload=True)
app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True


app.layout = html.Div(children=[

    html.H2('MWE', style={'font-size':'26px'}),
    
    html.Div(children=[
                       html.Label("Input Var's",
                                  style={'grid-row':'1 / 2', 'grid-column':'1 / 2'}),
                       dcc.Input('Input', type='text',
                                  style={'grid-row':'2 / 3', 'grid-column':'1 / 2'}),
    
                       html.Label('# of Inputs',
                                  style={'grid-row':'1 / 2', 'grid-column':'2 / 3'}),
                       dcc.Input(id='Random 1', value=10, type='number',
                                  style={'grid-row':'2 / 3', 'grid-column':'2 / 3'}),
        
                       html.Label('Random 2',
                                  style={'grid-row':'1 / 2', 'grid-column':'3 / 4'}),
                       dcc.Input(id='Random 3', value=10, type='number',
                                  style={'grid-row':'2 / 3', 'grid-column':'3 / 4'}),
        
                       html.Button(id='Button 1', children='Button 1',
                                   style={'grid-row':'2 / 3', 'grid-column':'4 / 5'}),
        
        
                       html.Button(id='Button 2', children='Button 2',
                                   style={'grid-row':'2 / 3', 'grid-column':'5 / 6'}),
        
                       html.A(html.Button(children='Save Button', id='table_download_button',
                                          style={'grid-row':'2 / 3', 'grid-column':'6 / 7'}),
                              id='table_download_link',
                              download="raw_tweet_data.csv",
                              href="",
                              target="_blank"),

    ],
              style={'display':'grid', 'grid-template-rows':'25px 25px 25px 25px', 
                     'grid-auto-columns': '100px 100px 100px 100px 140px 140px '}
            )

])
    
    
        mport dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html


app = dash.Dash(dev_tools_hot_reload=True)
app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True


app.layout = html.Div(children=[

    html.H2('MWE', style={'font-size':'26px'}),
    
    html.Div(children=[
                       html.Label("Input Var's",
                                  style={'grid-row':'1 / 2', 'grid-column':'1 / 2'}),
                       dcc.Input('Input', type='text',
                                  style={'grid-row':'2 / 3', 'grid-column':'1 / 2'}),
    
                       html.Label('# of Inputs',
                                  style={'grid-row':'1 / 2', 'grid-column':'2 / 3'}),
                       dcc.Input(id='Random 1', value=10, type='number',
                                  style={'grid-row':'2 / 3', 'grid-column':'2 / 3'}),
        
                       html.Label('Random 2',
                                  style={'grid-row':'1 / 2', 'grid-column':'3 / 4'}),
                       dcc.Input(id='Random 3', value=10, type='number',
                                  style={'grid-row':'2 / 3', 'grid-column':'3 / 4'}),
        
                       html.Button(id='Button 1', children='Button 1',
                                   style={'grid-row':'2 / 3', 'grid-column':'4 / 5'}),
        
        
                       html.Button(id='Button 2', children='Button 2',
                                   style={'grid-row':'2 / 3', 'grid-column':'5 / 6'}),
        
                       html.A(html.Button(children='Save Button', id='table_download_button',
                                          style={'grid-row':'2 / 3', 'grid-column':'6 / 7'}),
                              id='table_download_link',
                              download="raw_tweet_data.csv",
                              href="",
                              target="_blank"),

    ],
              style={'display':'grid', 'grid-template-rows':'25px 25px 25px 25px', 
                     'grid-auto-columns': '100px 100px 100px 100px 140px 140px '}
            )

])
    
    
    
if __name__ == '__main__':
    app.run_server(debug=True)
if __name__ == '__main__':
    app.run_server(debug=True)
1 Like

Just as an update: I want to be able to do this,

, instead of this,

the way i handle this is i just put a button inside the html that does nothing when push but still fires anithing withing the html A
like this:
html.A(
[html.Button(‘SOME TEXT’, className=‘excel’)],
target=’_blank’, download=href_link, id=f’-excel-link’,
href=href_link
)
this way you can have a html A that looks like a button.
and one you have this button you can just add a style parameter or a css class should work
hope this help

2 Likes

I tried doing what you recommended, putting className='excel' under both the html.Button, and the html.Div encompassing it, but that does not do anything for some reason.

Rather than styling this one Button the correct way, I want to stop whatever is preventing it from inheriting the other Buttons’ style.

For example, this does not seem to solve the issue, explicitly giving html.A the same class as html.Div:

import dash
import dash_core_components as dcc
import dash_html_components as html


app = dash.Dash(dev_tools_hot_reload=True)
app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True


app.layout = html.Div(children=[

    html.H2('MWE', style={'font-size':'26px'}),
    
    html.Div(children=[
                       html.Label("Input Var's",
                                  style={'grid-row':'1 / 2', 'grid-column':'1 / 2'}),
                       dcc.Input('Input', type='text',
                                  style={'grid-row':'2 / 3', 'grid-column':'1 / 2'}),
    
                       html.Label('# of Inputs',
                                  style={'grid-row':'1 / 2', 'grid-column':'2 / 3'}),
                       dcc.Input(id='Random 1', value=10, type='number',
                                  style={'grid-row':'2 / 3', 'grid-column':'2 / 3'}),
        
                       html.Label('Random 2',
                                  style={'grid-row':'1 / 2', 'grid-column':'3 / 4'}),
                       dcc.Input(id='Random 3', value=10, type='number',
                                  style={'grid-row':'2 / 3', 'grid-column':'3 / 4'}),
        
                       html.Button(id='Button 1', children='Button 1',
                                   style={'grid-row':'2 / 3', 'grid-column':'4 / 5'}),
        
        
                       html.Button(id='Button 2', children='Button 2',
                                   style={'grid-row':'2 / 3', 'grid-column':'5 / 6'}),
        
                       html.A(html.Button(children='Save Button', id='table_download_button',
                                                                                    
                                          style={'grid-row':'2 / 3', 'grid-column':'6 / 7'}),
                              
                              className='excel',
                              
                              id='table_download_link',
                              download="raw_tweet_data.csv",
                              href="",
                              target="_blank"),

    ],
             className='excel',
             
             style={'display':'grid', 'grid-template-rows':'25px 25px 25px 25px', 
                     'grid-auto-columns': '100px 100px 100px 100px 140px 140px '}
            )

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

the excel class is a custom CSS class i have in my assests folder that may be the reasion why it does nothing try use another class. in an older user case i have i manage to inherit a css class of a button directly to the html A tag like this:
html.A(
‘Some text’, href=’/’, id=‘id’,
className=‘btn btn-default’
)
You may also try this.

image
this is the result of the code above (ignore text in spanish :grin:)

That is an interesting trick you used at some point, and I will have to look into the default classes - and how to inherit them - in Dash, but unfortunately it did not work for me :disappointed:

import dash
import dash_core_components as dcc
import dash_html_components as html


app = dash.Dash(dev_tools_hot_reload=True)
app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True


app.layout = html.Div(children=[

    html.H2('MWE', style={'font-size':'26px'}),
    
    html.Div(children=[
                       html.Label("Input Var's",
                                  style={'grid-row':'1 / 2', 'grid-column':'1 / 2'}),
                       dcc.Input('Input', type='text',
                                  style={'grid-row':'2 / 3', 'grid-column':'1 / 2'}),
    
                       html.Label('# of Inputs',
                                  style={'grid-row':'1 / 2', 'grid-column':'2 / 3'}),
                       dcc.Input(id='Random 1', value=10, type='number',
                                  style={'grid-row':'2 / 3', 'grid-column':'2 / 3'}),
        
                       html.Label('Random 2',
                                  style={'grid-row':'1 / 2', 'grid-column':'3 / 4'}),
                       dcc.Input(id='Random 3', value=10, type='number',
                                  style={'grid-row':'2 / 3', 'grid-column':'3 / 4'}),
        
                       html.Button(id='Button 1', children='Button 1',
                                   style={'grid-row':'2 / 3', 'grid-column':'4 / 5'}),
        
        
                       html.Button(id='Button 2', children='Button 2',
                                   style={'grid-row':'2 / 3', 'grid-column':'5 / 6'}),
        
                       html.A(html.Button(children='Save Button', id='table_download_button',
                                                                                    
                                          style={'grid-row':'2 / 3', 'grid-column':'6 / 7'}),
                              
                              ###################################################
                              ############# Using recommended class #############
                              ###################################################
                              className='btn btn-default',
                              
                              id='table_download_link',
                              download="raw_tweet_data.csv",
                              href="",
                              target="_blank"),

    ],
             
             style={'display':'grid', 'grid-template-rows':'25px 25px 25px 25px', 
                     'grid-auto-columns': '100px 100px 100px 100px 140px 140px '}
            )

])
    


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

give this a try please:
html.A(‘Save Button’,
id=‘table_download_link’,
download=“raw_tweet_data.csv”,
href="",
className=‘btn btn-default’,
style={‘grid-row’:‘2 / 3’, ‘grid-column’:‘6 / 7’},
target="_blank")

1 Like

Trying a variation on what you recommended,

html.A(children=html.Button(children='Save Button'),

id='table_download_link',
className='btn btn-default',

download='raw_tweet_data.csv',
href="",
target="_blank",
style={'grid-row':'2 / 3', 'grid-column':'6 / 7'})

actually partially ended up working for me! Thanks a lot!

29%20PM

The button is lined up now, and its clickable border extends as far as it should (as far as the other html.Button’s areas), but the style is still not where it should be.

Could you give me another hint as how to make the html.A tag also achieve the button look?

You need to switch the order. Put the html.A as the 'children'of the html.Button.

1 Like

Even more success!

Except now (besides the underlining), the save prompt only initiates if “the text”, or “Save Button” gets pressed, whereas pressing the outer gray area of the html.Button does nothing.

Is there an easy fix for this? Whereas before, the whole of the button acted as a download prompt, now the button has the right style, but only clicking the text activates the download prompt.

sorry i didn’t answer that would be expected if you have you code like this

html.Button(children=html.A(children=‘Save Button’)

because in that case pushing the button would not fire any event you have in the A tag since it’s outside of it

The closest I have been able to get on my own research, is the following to get html.A to look like html.Button:

html.A(children='Save Button', 
        id='table_download_link',                                
        download='raw_tweet_data.csv',
        href="",
        target="_blank",
        style={ '-webkit-appearance': 'button', '-moz-appearance': 'button',
                'appearance': 'button', 'text-decoration': 'none', 'cursor': 'default',
                'color': 'initial'})

The only remaining problems(for future development!) is that the text in the button can be out of place, and I’m not sure how to change its font/size.

For now, I think I’ll settle for

html.A(html.Button(children='Save to CSV', id='table_download_button'),
       id='table_download_link', download="raw_tweet_data.csv", href="", target="_blank"),

, as it at least produces a minimal, no complications, no-frills button.

Thanks for all the help so far, guys!