0 votes
by (730 points)

I'm trying to style all the checkbox macros, I've looked up tutorials online and they don't seem to be working properly (I followed this tutorial which uses ::before and ::after stuff but it doesn't seem to work as well with a <<checkbox>> macro). How do you style checkbox macros?

2 Answers

+1 vote
by (159k points)

note: the following descriptions are based on the examples included in the <<checkbox>> macro documentation.

If you use your web-browser's built-in Web Developer Tools to inspect the HTML elements generated by the macro you will see that it looks something like the following.

<input id="checkbox-pieblueberry" name="checkbox-pieblueberry" type="checkbox" tabindex="0" class="macro-checkbox">

.. and that the following CSS rules are being used to apply that element default styling.

button, input, optgroup, select, textarea {
    color: inherit;
    font: inherit;
    margin: 0;

input {
    line-height: normal;

input, select, textarea {
    color: #eee;
    background-color: transparent;
    border: 1px solid #444;
    padding: .4em;

input[type=checkbox], input[type=radio] {
    box-sizing: border-box;
    padding: 0;

input[type=checkbox], input[type=file], input[type=radio], select {
    cursor: pointer;

The CSS selectors in the article you linked to assume that they are being applied to the following HTML structure, which is wrapping the 'checkbox' <input> element within a .checkbox classed parent <div> element, they also assume that the <label> element is a later sibling of the <input> element.

<div class="checkbox">
    <input type="checkbox" id="checkbox_1">
    <label for="checkbox_1">Pure CSS Checkbox</label>

So unless you have structured your Passage content like the following then all the above assumtions will be false, and this would be the reason why the CSS rules in the article aren't working.

<div class="checkbox">\
    <<checkbox "$pieBlueberry" false true checked>>\
    <label for="checkbox-pieblueberry">Blueberry?</label>\


+1 vote
by (44.7k points)
edited by

I turned the checkbox in that tutorial into a widget.  To use it, first create a passage, give it "widget" and "nobr" tags (tag names must be lowercase), and put the following code in that widget passage:

/*	<<checkit>> widget
	This allows you to display a custom checkbox which sets a SugarCube
	variable, displays a (clickable) label, and satisfies accessibility
	guidelines for users with impairments (i.e. works with TAB focus).
	Checkboxes will be checked appropriately depending on the value of
	the variable passed to it (which will be converted to a boolean, if
	it's not already a boolean value).

		<<checkit "$variableName" "Label text">>
<<widget "checkit">>
	/* Make sure the variable passed in is a boolean. */
	<<set State.setVar($args[0], !!State.getVar($args[0]))>>
	<<if ndef _checkboxIDno>>
		/* Start checkbox IDs at 1. */
		<<set _checkboxIDno = 1>>
		/* Next checkbox ID. */
		<<set _checkboxIDno += 1>>
	<<set _checkboxData = "'" + $args[0] + "'">>
	/* Display checkbox. */
	<span class="checkbox" tabindex="0" onkeyup="if (event.key == ' ') { $(this).find('input[type=\'checkbox\']').trigger('click'); }">
		<<print '<input type="checkbox" id="checkbox_' + _checkboxIDno + '" tabindex="-1" onchange="SugarCube.State.setVar(' + _checkboxData + ', this.checked)" data-var="' + $args[0] + '"' + (State.getVar($args[0]) ? ' checked' : '') + '>'>>
		<label @for="'checkbox_' + _checkboxIDno">

Then add this to your Stylesheet section:

/* Prevent double-clicks from selecting the text */
.checkbox {
	-webkit-touch-callout: none; /* iOS Safari */
	-webkit-user-select: none;   /* Safari */
	 -khtml-user-select: none;   /* Konqueror HTML */
	   -moz-user-select: none;   /* Firefox */
	    -ms-user-select: none;   /* Internet Explorer/Edge */
		user-select: none;   /* Non-prefixed version, currently
					supported by Chrome and Opera */
	display: inline-block;
	line-height: 27px;
.checkbox input[type="checkbox"] {
	display: none;
	opacity: 0;
.checkbox label {
	position: relative;
	display: inline-block;
	padding-left: 25px;
	padding-right: 5px;
	line-height: 25px;
.checkbox label::before,
.checkbox label::after {
	position: absolute;
	content: "";
	display: inline-block;
/* Outer box of the fake checkbox */
.checkbox label::before {
	height: 16px;
	width: 16px;
	left: 3px;
	top: 4px;
	border: 1px solid;
/* Checkmark of the fake checkbox */
.checkbox label::after {
	height: 5px;
	width: 9px;
	left: 7px;
	top: 8px;
	border-left: 2px solid;
	border-bottom: 2px solid;
	transform: rotate(-45deg);
/* Hide the checkmark by default */
.checkbox input[type="checkbox"] + label::after {
	content: none;
/* Unhide on the checked state */
.checkbox input[type="checkbox"]:checked + label::after {
	content: "";
/* Adding focus styles on the outer-box of the fake checkbox */
.checkbox:focus input[type="checkbox"] + label::before {
	border-color: rgb(59, 153, 252);

Now, once you've done that, adding checkboxes is as easy as this:

<<checkit "$check1" "CSS Checkbox 1">>
<<checkit "$check2" "CSS Checkbox 2">>
<<checkit "$check3" "CSS Checkbox 3">>

See the comments at the top of the widget for an explanation of how it works.

Hope that helps!  :-)

by (730 points)
I tried your widget but it's not working, says:


Error: <<checkit>>: errors within widget contents (Error: <<set>>: bad evaluation: State.getVar is not a function; Error: <<print>>: bad evaluation: State.getVar is not a function)
by (63.1k points)
Sounds like you are using a very old version of SugarCube.
by (730 points)

I'm pretty sure the story format is set to Sugarcube 2.21, unless that is an older version of Sugarcube? Either way I followed greyelf's method instead, since I already wrapped the checkbox in a div and all I had to do was fix the <label> tag.

by (44.7k points)
edited by

Yeah, sorry, .getVar() and .setVar() are from SugarCube v2.22.0.  The current version of SugarCube is v2.28.2, which has a number of bugfixes and improvements.

You can download the latest version of SugarCube from here and the installation instructions are here.  (Tip: When adding the format,js file to Twine, it's easiest to first drag-drop the file on a browser window, and then copy the URL from the browser to Twine.)

That should make the code work for you.