Definition of checklist objects with markdown formatted labels

Hi, wanting a checklist of items that may contain clickable links I used labels with markdown text in dcc.Checklist which didn’t work, of course. The definition below served my purpose but I don’t dare to think of the need to define callbacks for finding which items are currently selected. Can anyone think of a better solution?

def checklist_markdown(options) -> dbc.Col:
    r''' Return html.Col() for the list of each entry of `options` mapped to
            an enumerating number,
            a checkbox, and
            a label

        Parameters:
        options=[
            {
                'label': "<markdown text representing the item in the list>",
                'id'   : "<identifier to be used in callbacks>",
                'value': "<value to check for in callbacks>"
            },
            ...
        ]
    '''
    def list_item(start,total,value,label,identifier):
        r'''Return `html.Ol` object with couting starting at `number` that only contains
            one `dbc.Row` element containing
                - a one-element `dcc.Checklist` with property `id=identifier` set to `value` when clicked
                - a `dbc.Row` element that contains a `dcc.Markdown` element to process `label`

            Parameters:
            start                   ... to start counting in the ordered list at
            total                   number of all items in the list
            label                   markdown text representing the item in the list
            identifier              ... to be used in callbacks
            value                   ... to check for in callbacks
        '''
        format_str = "{:" + str(len(str(total))) + "d}"
        logger.info(f'{checklist_markdown.__name__}.{list_item.__name__}: {format_str=},')
        label_number = dbc.Col(
            dcc.Markdown(format_str.format(start)),
            width="auto",
        )
        # logger.info
        print(f'{checklist_markdown.__name__}.{list_item.__name__}: using format code "{format_str=}" for displaying {start=}')
        html_checkbox = dbc.Col(
            dcc.Checklist(
                id=identifier,
                options=[ { 'label': ' ', 'value': value } ],
            ),
            width=1,
        )
        label_markdown = dbc.Col(
            dcc.Markdown(label),
            width=8,
        )
        children = dbc.Row([label_number, html_checkbox, label_markdown])
        html_list_item = html.Ol(children, start = str(start))
        return  html_list_item

    total = len(options)
    return dbc.Col(
        [list_item(i+1, total, options[i]['value'], options[i]['label'], options[i]['id']) for i in range(total)],
        width={"offset": 1}
    )

Hi @schwabts if you are just interested in the clickable lable, you could use html.A() but maybe I am missing something…

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Checklist(
        id='check',
        options=[
            {
                'label': html.A(
                    children=f'click_{idx}',
                    href='https://dash.plotly.com/dash-html-components/a',
                    target="_blank"
                ),
                'value': idx
            } for idx in range(4)]
    )
])


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

Hi AIMPED,
thank you very much for pointing this out!

However, my approach was based on pure markdown checklists using the [ and ] syntax which allows me to use all other markdown formatting options, too. Then I would simply provide dcc.Markdown() with the respective markdown source code.
My problems to solve were

  1. make the checkboxes clickable.
  2. detect selection of checklist items.

I provided the solution to problem 1. and your example solves problem 2.
On the other hand your example does not allow me to simply define the labels in full markdown syntax.

Can anyone think of how to solve both problems 1. and 2.?

PS: I’m sorry, for not having provided a minimal running example. I first thought using my function checklist_markdown(options) above as follows would be simple enough and I wanted to save time. I confirmed the function works as expected but still did not test this reduced code:

app = dash.Dash(__name__)

app.layout = html.Div(
    [
        checklist_markdown(
                options=[
                    {
                        "label": "item 1 refers to [World Time Buddy](https://www.worldtimebuddy.com/)",
                        'id'   : 'id-time',
                        "value": "weekend"
                    },
                    {
                        "label": "dummy item 2",
                        'id'   : 'id-dummy',
                        "value": "dummy"
                    }
        )
    ]
)

def checklist_markdown(options) -> dbc.Col:
    r''' Return html.Col() for the list of each entry of `options` mapped to
            an enumerating number,
            a checkbox, and
            a label

        Parameters:
        options=[
            {
                'label': "<markdown text representing the item in the list>",
                'id'   : "<identifier to be used in callbacks>",
                'value': "<value to check for in callbacks>"
            },
            ...
        ]
    '''
    def list_item(start,total,value,label,identifier):
        r'''Return `html.Ol` object with couting starting at `number` that only contains
            one `dbc.Row` element containing
                - a one-element `dcc.Checklist` with property `id=identifier` set to `value` when clicked
                - a `dbc.Row` element that contains a `dcc.Markdown` element to process `label`

            Parameters:
            start                   ... to start counting in the ordered list at
            total                   number of all items in the list
            label                   markdown text representing the item in the list
            identifier              ... to be used in callbacks
            value                   ... to check for in callbacks
        '''
        format_str = "{:" + str(len(str(total))) + "d}"
        logger.info(f'{checklist_markdown.__name__}.{list_item.__name__}: {format_str=},')
        label_number = dbc.Col(
            dcc.Markdown(format_str.format(start)),
            width="auto",
        )
        # logger.info
        print(f'{checklist_markdown.__name__}.{list_item.__name__}: using format code "{format_str=}" for displaying {start=}')
        html_checkbox = dbc.Col(
            dcc.Checklist(
                id=identifier,
                options=[ { 'label': ' ', 'value': value } ],
            ),
            width=1,
        )
        label_markdown = dbc.Col(
            dcc.Markdown(label),
            width=8,
        )
        children = dbc.Row([label_number, html_checkbox, label_markdown])
        html_list_item = html.Ol(children, start = str(start))
        return  html_list_item

    total = len(options)
    return dbc.Col(
        [list_item(i+1, total, options[i]['value'], options[i]['label'], options[i]['id']) for i in range(total)],
        width={"offset": 1}
    )

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

Hello @schwabts,

You could actually create something in dash_table or AG Grid, both support Markdown, and you can make the cells selectable.

Hmm, the label does also accept a dcc.Markdown() component

Hi AIMPED!
I just confirmed that, thank you so much!
I would just have needed to note but missed the doc’s section

However,

  1. the function I provided numbered my checklist items which I had not posed as a problem to solve but I consider it “nice to have”, anyway.
  2. dcc.Markdown() components as labels seem to start on a new line and extend over the full width of the browser window whereas the dbc.Col(..., width={"offset": 1})component that the function I provided returns is centered on the page I am working on. Simply putting the dcc.Checklist() inside a dbc.Col(..., width={"offset": 1}) did indent the checklist but it is still formatted ragged right.

So I’ll keep using my function as it displays my list in a way that is more helpful for me.
However, the posed problems are solved and your answer is therefore accepted.