dash_table.DataTable Embedded Links

Is there anywhere I can find the css stylesheet for DataTable? I need to create an html table instead of using DataTable because I want to embed links inside of the cells. But I want to the html table to look the same as the DataTable and resize in the same manner.

FWIW, this is now possible with the new markdown presentation option in dash_table.

Your best bet would probably be to use your browser’s “Inspect Element” feature and inspect the CSS styles manually.

2 Likes

Ah I didn’t realize markdown presentation was now possible! Has it made it’s way into the DataTable documentation yet?

Not really unfortunately. Here’s an example in the meantime:

data=[
    dict(a=''' ```javascript
return 20;
    ```
'''), # need to dedent the ``` for actual usage
    dict(a='''An image\n
![Plotly](https://global.discourse-cdn.com/business7/uploads/plot/original/2X/7/7957b51729ad7fd9472879cd620b9b068d7105bb.png)'''),
    dict(a='''
_italics_\n
**bold**\n
~~strikethrough~~
'''),
    dict(a='''Nested table
Statement | Is it true?
--- | ---
This page has two tables | yes
This table has two rows | no
This is an example of tableception | yes
'''),
    dict(a='[Dash documentation](https://dash.plot.ly)')
]

app.layout = Div([
    DataTable(
        columns=[
            dict(name='a', id='a', type='text', presentation='markdown'),
        ],
        css=[
            dict(selector='img[alt=Plotly]', rule='height: 50px;')
        ],
        data=data
    ),
])

The user interaction is a little awkward, you have to click the link twice to open it (once to select the cell, a second time to press the link). That issue is logged here: Clicking on a markdown link should open the link rather than selecting the cell · Issue #710 · plotly/dash-table · GitHub

1 Like

How would I style the markdown? textAlign, fontFamily, fontSize don’t seem to be working inside of style_cell_conditional

Hm good question. What’s the recommendation here @Marc-Andre ?

Hi!

I tried dbc bootstrap table to embed the link, it was working great.

import pandas as pd
import dash_bootstrap_components as dbc

title=['Hi Dash','Hello World']
link=[html.A(html.P('Link'),href="yahoo.com"),html.A(html.P('Link'),href="google.com")]

dictionary={"title":title,"link":link}
df=pd.DataFrame(dictionary)
table=dbc.Table.from_dataframe(df, striped=True, bordered=True, hover=True)

Now this table can be returned to your child element through function calling according to your rules.

6 Likes

There is no “official” API to override the Markdown styles inside the DataTable. You can either include a css file in the app’s /assets folder or use the table’s css. You can apply a specific style for row/columns with data-dash-row and data-dash-column attributes. For example:

import dash
from dash_html_components import Div
from dash_table import DataTable

app = dash.Dash(__name__)

md='''Nested table
Statement | Is it true?
--- | ---
This page has two tables | yes
This table has two rows | no
This is an example of tableception | yes
'''

data=[
    dict(a=md, b=md),
    dict(a=md, b=md),
]

app.layout = Div([
    DataTable(
        columns=[
            dict(name='a', id='a', type='text', presentation='markdown'),
            dict(name='b', id='b', type='text', presentation='markdown'),
        ],
        css=[
            #
            dict(selector='td table', rule='font-size: 16px;'),
            dict(selector='td table tr > *', rule='text-align: left;'),
            dict(selector='td[data-dash-row="1"] table', rule='font-size: 20px;'),
            dict(selector='td[data-dash-row="1"][data-dash-column="b"] table', rule='font-family: cursive;')
        ],
        data=data
    ),
])

app.run_server(debug=True)

Note that when using the css prop, the final selector will be prepended with a selector that is specific to the table for which the css prop is defined. Styles will not leak between tables. If using a css file instead, I suggest giving the DataTable an id to isolate styles on a per-table basis.

A close css equivalent, with id would be:

#my-table-id td table {
  font-size: 16px;
}

/* Etc. */

Hey, I am not sure if that is planned but when you embed link in datatable, it seems that it makes the whole datatable padded (aka there is big gap on top and bottom of each cell) . Here are two pics, one without links and other with links. Do you know how to avoid that (X is the link). Thanks!
Screenshot_20200606_210144
Screenshot_20200606_202733

1 Like

I had the same issue with the extra padding after adding hyperlinks, @mjk7ha. The only workaround I found that removed the padding was to load an external css stylesheet. Probably don’t need the whole stylesheet, but I’m not well versed enough in css to pick out exactly what’s needed.

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

THANK YOU SOOOO MUCH. OH GOD.
Btw, if anyone is interested, the magic piece of CSS that get rids of these margins when using hyperlinks is following:

p {
  margin-top: 0; }
1 Like

Here is the resulting table from arjun’s code. The hyperlinks will be relative URL’s unless you prefix them with https://www.

I like the idea of using this but combine with an auto generated link list… has anyone had success in appending dash html components to a python list? It is stripping the element tag every time I try.

Example:

link=[html.A(html.P('Link'), href="https://www.yahoo.com", target='_blank'), html.A(html.P('Link'), href="google.com", target='_blank')]

Auto generated result… by appending

html.A(html.P('Link'), href="https://www.yahoo.com", target='_blank')

to a the link list returns:

link=[A(children=P('Link'), href="https://www.yahoo.com", target='_blank'), A(children=P('Link'), href="google.com", target='_blank')]

I ended up writing functions to make the rows, and another one make the cells. My actual code also has to create a bunch of buttons, but I made in more generic to share here, you can just take the url into the data frame in a special column and then do this:


def make_table_from_df2(_df, columns=None):
    if _df.empty:
        return html.Table()
    if columns is None:
        columns = _df.columns
    data_dict = _df[columns].to_dict(orient='records')

    col_names = list(data_dict[0].keys())
    header_column_cells = [
        html.Th(x) for x in col_names if not x.startswith('_')
    ]
    table_header = [html.Thead(html.Tr(header_column_cells))]
    table_body = [html.Tbody([make_row2(x, col_names) for x in data_dict])]
    return table_header + table_body


def make_row2(data_dict_entry, col_names):
    def process_cell_links(col_name, link_names):
        """Add links to tables in the right way."""
        if (thehref := f"{col_name}_HREF") in link_names:
            return dcc.Link(str(data_dict_entry[col_name]),
                            href=str(data_dict_entry[thehref]))
        else:
            return str(data_dict_entry[col_name])

    link_names = [x for x in col_names if x.endswith('_HREF')]
    return html.Tr([
        html.Td(process_cell_links(x, link_names)) for x in col_names
        if not x.endswith('_HREF')
    ])

EDITED: to fix a mistake in make_row2

You can then use this by doing something like dbc.Table(make_table_from_df2(df))

and any column say named “Country” would get a link if it had another column named “Country_HREF” with the href being the value in that matching column.

You could alter dcc.Link if you knew you always wanted it in a new window, adding target=’_blank’

Of course want I want is to have links that this and sortable columns, so I guess I’ll have to write a callback instead of using DataTable.

Working on getting this into a module, work in progress here: