7

In Markdown using <input type="checkbox"/> or - [ ] there will give me a white box, which can not be checked by click. Any idea how to implement there a clickable checkbox for progress documentation. I guess i need a extension but which is working for jupyterlab?

Example:

  • [ ] do this and that and then do that (so longer tex)
  • [ ] another long text
  • [ ] click to document your progess, put after finishing the task, no saving is needed of the checkmarks.
user23657
  • 131
  • 1
  • 2
  • 11

3 Answers3

6

while - [ ] gives you empty checkboxes, - [x] will be rendered as a checked checkbox. Here's a demo in GitHub's flavor:

- [ ] unchecked
- [x] checked

which will be rendered as:

enter image description here

Note that things like HTML radio buttons and checkboxes, while interactive, are not permanent changes on your document unless you have a backend code to save the changes by changing the HTML tags.

See this:

label {
  padding-left: 5px;
}

input {
  float: left;
}
<div>
  <input type="checkbox" name="uchk">
  <label for="uchk">Unchecked.</label>
</div>
<div>
  <input type="checkbox" name="chk" checked>
  <label for="chk">Checked.</label>
</div>

Furthermore, I don't think you'd really want your markdown document to have clickable checkboxes, it reduces from immersion and also if they are going to be permanent it's easy for anyone to change it.

M.H. Tajaddini
  • 776
  • 4
  • 20
  • 1
    I know that manually I can check them with typing an x, but I really need them to be checked interactively via a click for users not seeing the raw Markdown code. I know that in HTML code it is possible to have checkboxes, but i need to have it in an executed markdown cell in Jupterlab, there your and mine example is not activatable via click – user23657 Mar 31 '21 at 18:58
  • @user23657 I don't think this is achievable this way. I suggest converting your project to a webpage for this, because even if you do pull this off it'll most probably be a hacky way and not really maintainable. Please do follow up though, if you find a solution. I've bookmarked your question. Since you're using python, you might want to check flask or django as your backend solution. – M.H. Tajaddini Apr 01 '21 at 14:27
2

One option is to use ipywidgets, which is a Python library that provides form widgets specifically for Jupyter Notebook/Labs.

To display a Checkbox:

from ipywidgets import Checkbox
mycheckbox = Checkbox()
display(mycheckbox)

That will display a checkbox, which you can check and uncheck. However, the state of the checkbox will not be saved. Each time you re-run the notebook or restart the kernal, the checkbox will be recreated with its default value (False).

If you would like the checkbox to be created with a saved value, then you need to get that value and and pass it in when creating the checkbox.

mycheckbox = Checkbox(value=myvalue)

But, of course, you then need to retrieve that value first. You also need to save the value when it changes so that you can retrieve it next time. For the example below, I have used a JSON file to store the value. Of course, the example could be adapted to use any valid method for storing persistent data.

Let's assume we have a file named data.json which contains the following:

{"item": true}

Then, in our notebook, we run this Python code:

from ipywidgets import Checkbox
import json

with open('data.json', 'r') as f:
    data = json.load(f)

item = Checkbox(value=data['item'], description='item')

def on_value_change(change):
    key = change['owner'].description
    value = change['new']
    
    data[key] = value
    with open('data.json', 'w') as f:
        json.dump(data, f)

item.observe(on_value_change, names='value')
display(item)

Let's break that down.

First we load the JSON data into the Python dict: data.

with open('data.json', 'r') as f:
    data = json.load(f)

Then we create the checkbox, using the value obtained from the JSON file.

item = Checkbox(value=data['item'], description='item')

But we also need to detect any changes to the checkbox. So we need to define a change handler.

def on_value_change(change):
    key = change['owner'].description
    value = change['new']
    
    data[key] = value

    with open('data.json', 'w') as f:
        json.dump(data, f)

The first two lines obtain the name of the item and the new value. Then we update the data with the new value. Finally, we write the updated data to our JSON file.

Finally, we need to tell the checkbox about our handler by passing it to the observe method:

item.observe(on_value_change, names='value')

Note that we pass names='value' to observe so that only changes to the value are received (anything else will get ignored).

Below is a slightly modified version which prints output informing you each time the data file is updated:

from ipywidgets import Checkbox, Output
import json

with open('data.txt', 'r') as f:
    data = json.load(f)

item = Checkbox(value=data['item'], description='item')
out = Output()

@out.capture()
def on_value_change(change):
    key = change['owner'].description
    value = change['new']
    
    print(f'Saving value: "{{ \'{key}\': {value} }}"')
    
    data[key] = value
    with open('data.txt', 'w') as f:
        json.dump(data, f)

item.observe(on_value_change, names='value')
display(item)
display(out)

Run that and each time you click the checkbox, a message will get printed below it showing what was saved.

Saving value: "{ 'item': False }"
Saving value: "{ 'item': True }"
Saving value: "{ 'item': False }"

It can be useful for debugging purposes. By adding more print statements you can determine what other information is contained in the change variable. which may help in adapting this to fit your needs.

Waylan
  • 37,164
  • 12
  • 83
  • 109
  • thanks for the detailed answer. for me it is no problem, that the values will not be saved in general but nice workaround with json. I would prefer to have the checkboxes in a markdown cell, as there will be a lot of text and then the user will not see any code, is there a way to integrate widgets there or any extension for this? – user23657 Apr 02 '21 at 11:50
  • A Markdown cell is rendered as HTML. You could basically do the same thing in JavaScript to save the state of the checkboxes – Waylan Apr 02 '21 at 14:05
  • ok even if i put it in a code cell the length of the labels is limited, so if I need longer text next to the checkbox, it will not be shown completely, is there a solution for that? – user23657 Apr 02 '21 at 15:16
  • with the workaround [here](https://github.com/jupyter-widgets/ipywidgets/issues/861) i am not able to have multiline text, also inserting \n does not help – user23657 Apr 02 '21 at 17:22
1

You can integret HTML <input type="radio"/> instead, and change the style to look like a checkbox.

Mentroz
  • 11
  • 2
  • as far as i know with radio it is only possible to choose one thing at once. Further i got the same issue that it is not activated by click – user23657 Mar 31 '21 at 10:08