10  More Plugins

learning goals
  • Review how to add new plugins to jsPsych experiments
  • Learn to navigate and interpret jsPsych plugin documentation
  • Practice implementing the instructions and html-button-response plugins
  • Understand how to customize plugin parameters and styling

10.1 Introduction

In this chapter, we’re going to take a closer look at adding plugins to your jsPsych experiments and learning how to read the official documentation. We’ll focus on two specific plugins: the html-button-response plugin, which lets participants click on buttons to respond, and the instructions plugin plugin, which creates multi-page instruction screens.

Since this book can’t cover every single plugin, our main goal here is to teach you how to read and understand the documentation. Once you master this skill, you’ll be able to add any plugin you need to your experiments, even ones we haven’t discussed.

Think of plugin documentation as a recipe book. Each plugin page tells you exactly what ingredients (parameters) you need, which ones are required versus optional, and how to put them together to create the trial you want.

10.2 The Instructions Plugin

10.2.1 Documentation Overview

When you visit the instructions plugin documentation, you’ll see several important sections. Let’s walk through each one so you know what to look for.

10.2.1.1 Parameters

The most important part of any plugin documentation is the parameters table. This table tells you everything you can customize about how the plugin works.

Parameter Type Default Value Description
pages array undefined Each element of the array is the content for a single page. Each page should be an HTML-formatted string.
key_forward string ‘ArrowRight’ This is the key that the participant can press in order to advance to the next page. This key should be specified as a string (e.g., ‘a’, ‘ArrowLeft’, ’ ‘, ’Enter’).
key_backward string ‘ArrowLeft’ This is the key that the participant can press to return to the previous page. This key should be specified as a string (e.g., ‘a’, ‘ArrowLeft’, ’ ‘, ’Enter’).
allow_backward boolean true If true, the participant can return to previous pages of the instructions. If false, they may only advace to the next page.
allow_keys boolean true If true, the participant can use keyboard keys to navigate the pages. If false, they may not.
show_clickable_nav boolean false If true, then a Previous and Next button will be displayed beneath the instructions. Participants can click the buttons to navigate.
button_label_previous string ‘Previous’ The text that appears on the button to go backwards.
button_label_next string ‘Next’ The text that appears on the button to go forwards.
show_page_number boolean false If true, and clickable navigation is enabled, then Page x/y will be shown between the nav buttons.
page_label string ‘Page’ The text that appears before x/y pages displayed when show_page_number is true.
on_page_change function function (current_page) {} The function that is called every time the page changes. This function receives a single argument current_page, which is the index of the current page after page change, and starts at 0. The function is also called when going forward from the last page, i.e., finishing the trial.

The pages parameter is the most important one. Notice that its default value is listed as undefined. This is a programming way of saying “nothing.” When you see “undefined” as a default value, it means this parameter is required. You must include it, or your trial won’t work. The pages parameter expects an array (a list) of content for each instruction page. Each item in your list becomes one page of instructions.

The show_clickable_nav parameter has a default value of false, which means by default, participants can only use keyboard keys to navigate through instructions. If you want to show “Previous” and “Next” buttons that participants can click, you need to change this to true.

Other parameters like button_label_next and button_label_previous let you customize what text appears on those navigation buttons. The default values are “Next” and “Previous,” but you might want to change them to something like “Continue” and “Back” depending on your experiment.

10.2.1.2 Install

The documentation also shows you how to load the plugin into your experiment. You’ll see a few options: loading it from a local file on your computer, or loading it from the internet using something called a CDN (Content Delivery Network).

Local method:

<script src="jspsych/plugin-instructions.js"></script>

Using the (online) CDN-hosted file:

<script src="https://unpkg.com/@jspsych/plugin-instructions@2.1.0"></script>

The CDN method is often easier because you don’t need to download and manage the plugin files yourself, but it requires an internet connection.

However, for this book, we’re using a local copy to ensure everyone is using the same version of jsPsych.

10.2.1.3 Examples

Further down the page, we can see a couple examples of creating an instructions trial object:

var trial = {
    type: jsPsychInstructions,
    pages: [
    'Welcome to the experiment. Click next to begin.',
    'This is the second page of instructions.',
    'This is the final page.'
    ],
    show_clickable_nav: true
}

Every jsPsych plugin follows the same naming pattern in your code. You take the plugin name (like “instructions”) and convert it to what programmers call “camelCase”. This means you capitalize the first letter of each word except the first, then add “jsPsych” to the beginning.

So the “instructions” plugin becomes jsPsychInstructions in your code. The “html-button-response” plugin becomes jsPsychHtmlButtonResponse. This might seem confusing at first, but once you see the pattern, it becomes automatic.

Also notice how we’re following the parameter requirements from the documentation. We specify the type as jsPsychInstructions, provide the required pages parameter with an array of three text strings, and set show_clickable_nav to true so participants can click buttons to navigate.

Each item in the pages array becomes one screen of instructions. Participants will see the first item first, then can navigate forward to see the second item, and so on.

10.2.2 A Working Example

Ok, let’s load it up and see it in action:

<!DOCTYPE html>
<html>
<head>
    <title>My experiment</title>
    <!-- Base JsPsych -->
    <script src="jspsych/jspsych.js"></script>
    <link href="jspsych/jspsych.css" rel="stylesheet" type="text/css" />
    
    <!-- Plugins -->
    <script src="jspsych/plugin-instructions.js"></script>
</head>
<body>
<script src="exp.js"></script>
</body>
</html>
const jsPsych = initJsPsych();
   var trial = {
    type: jsPsychInstructions,
    pages: [
    'Welcome to the experiment. Click next to begin.',
    'This is the second page of instructions.',
    'This is the final page.'
    ],
    show_clickable_nav: true,
    show_page_number: true,
    button_label_previous: "Back",
    button_label_next: "Next"
   }

jsPsych.run([trial])
Live JsPsych Demo Click inside the demo to activate demo

10.2.3 Adding HTML and Styling

Plain text instructions work fine, but sometimes you want more control over how your instructions look. Since the pages parameter accepts HTML, you can include formatting like headers, paragraphs, lists, and even custom styling.

Here’s a more sophisticated example:

<!DOCTYPE html>
<html>
<head>
    <title>My experiment</title>
    <!-- Base JsPsych -->
    <script src="jspsych/jspsych.js"></script>
    <link href="jspsych/jspsych.css" rel="stylesheet" type="text/css" />
    
    <!-- Plugins -->
    <script src="jspsych/plugin-instructions.js"></script>
    
    <!-- custom CSS -->
    <link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<script src="exp.js"></script>
</body>
</html>
const jsPsych = initJsPsych();

var trial = {
    type: jsPsychInstructions,
    pages: [
            `<div class="instructions">
              <h2>Welcome to the Memory Experiment!</h2>
              <p>In this study, you will be testing your working memory capacity using a digit span task. Use the arrow keys or buttons below to navigate through these instructions.</p>
            </div>`,

            `<div class="instructions">
              <h2>How the Task Works</h2>
              <p>You will see a sequence of numbers presented one at a time on the screen.</p>
              <p>Your job is to remember the numbers in the <strong>exact order</strong> they appeared. After the sequence ends, you will be asked to type the numbers back in the correct order.</p>
            </div>`,

            `<div class="instructions">
              <h2>Example</h2>
              <p>If you see the sequence: <code>3 → 7 → 1 → 9</code></p>
              <p>You should type: <code>3719</code></p>
              <p>The sequences will start short and gradually get longer as you progress through the experiment.</p>
            </div>`,

            `<div class="instructions">
              <h2>Important Guidelines</h2>
              <ul>
                <li>Pay close attention to each number as it appears</li>
                <li>Do not write anything down during the presentation</li>
                <li>Type your response as soon as the input box appears</li>
                <li>If you're unsure, make your best guess</li>
              </ul>
            </div>`,

            `<div class="instructions">
              <h2>Ready to Begin?</h2>
              <p>The experiment will take approximately 10-15 minutes to complete.</p>
              <p>Make sure you're in a quiet environment where you can concentrate.</p>
              <p>Click 'Next' when you're ready to start the practice trials.</p>
            </div>`
          ],
    show_clickable_nav: true
   }

jsPsych.run([trial])
.jspsych-content-wrapper {
      background-color: '#DCE2F0';
      color: '#50586C';
    }

.jspsych-content {
      width: 100%;
      max-width: 700px;
    }

.jspsych-btn {
      background-color: #4A5568; 
      color: #FFFFFF;
      border: 1px solid #2D3748;
    }
    
.jspsych-btn:hover {
      background-color: #2D3748;
    }

.instructions {
      margin-left: 1em;
      margin-right: 1em;
      text-align: left;
    }
    
Live JsPsych Demo Click inside the demo to activate demo

Notice a few important things about this example. First, I’m using backticks (`) instead of regular quotation marks around the HTML content. Backticks allow you to write text that spans multiple lines and includes quotation marks without causing problems in your code.

Second, I’ve wrapped each page’s content in a <div> with a class called instructions. This gives me a way to apply consistent styling to all my instruction pages using CSS.

Third, I’ve added the show_page_number parameter and set it to true. This will display something like “Page 1/3” to help participants understand how many instruction pages there are.

For the CSS, I’ve added some styling to our external stylesheet called style.css. I decided to change a few things about the jspsych classes, including the colors. This styling will apply to the entire experiment.

Then, I added our custom .instructions class and added some styling that will only apply to the instructions HTML.

10.3 The html-button-response Plugin

Now let’s move on to the html-button-response, which allows you to show HTML content and give participants buttons to click as their response.

10.3.1 Documentation Overview

When you look at the html-button-response, you’ll see it has quite a few parameters. Don’t let this overwhelm you as most of them are optional, and you only need to understand the ones relevant to your specific experiment

10.3.1.1 Parameters

Parameter Type Default Value Description
stimulus HTML string undefined The HTML content to be displayed.
choices array of strings [] Labels for the buttons. Each different string in the array will generate a different button.
button_html function (choice: string, choice_index: number)=> <button class="jspsych-btn">${choice}</button> A function that generates the HTML for each button in the choices array. The function gets the string and index of the item in the choices array and should return valid HTML. If you want to use different markup for each button, you can do that by using a conditional on either parameter. The default parameter returns a button element with the text label of the choice.
prompt string null This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention is that it can be used to provide a reminder about the action the participant is supposed to take (e.g., which key to press).
trial_duration numeric null How long to wait for the participant to make a response before ending the trial in milliseconds. If the participant fails to make a response before this timer is reached, the participant’s response will be recorded as null for the trial and the trial will end. If the value of this parameter is null, the trial will wait for a response indefinitely.
stimulus_duration numeric null How long to display the stimulus in milliseconds. The visibility CSS property of the stimulus will be set to hidden after this time has elapsed. If this is null, then the stimulus will remain visible until the trial ends.
button_layout string 'grid' Setting to ‘grid’ will make the container element have the CSS property display: grid and enable the use of grid_rows and grid_columns. Setting to ‘flex’ will make the container element have the CSS property display: flex. You can customize how the buttons are laid out by adding inline CSS in the button_html parameter.
grid_rows number 1 The number of rows in the button grid. Only applicable when button_layout is set to ‘grid’. If null, the number of rows will be determined automatically based on the number of buttons and the number of columns.
grid_columns number null The number of columns in the button grid. Only applicable when button_layout is set to ‘grid’. If null, the number of columns will be determined automatically based on the number of buttons and the number of rows.
response_ends_trial boolean true If true, then the trial will end whenever the participant makes a response (assuming they make their response before the cutoff specified by the trial_duration parameter). If false, then the trial will continue until the value for trial_duration is reached. You can set this parameter to false to force the participant to view a stimulus for a fixed amount of time, even if they respond before the time is complete.
enable_button_after numeric 0 How long the button will delay enabling in milliseconds.

The two most important parameters are stimulus and choices. Both of these have undefined as their default value, which means they’re required.

The stimulus parameter is where you put the content you want to show to participants. This could be a simple question, an image, a paragraph of text, or complex HTML with multiple elements. Think of this as the “question” part of your trial.

The choices parameter is an array (list) of the response options you want to give participants. Each item in this array becomes a clickable button. For example, if you want participants to choose between “Yes” and “No,” your choices array would be ['Yes', 'No'].

The button_html parameter is particularly interesting because it’s listed as a “function” rather than simple text. This parameter lets you completely control how your buttons look and behave. The default function creates a standard button with the choice text, but you can write your own function to create custom button designs. Don’t worry if this seems complicated right now. You can just use the default setting and still create perfectly functional experiments.

The prompt parameter allows you to add additional text that appears below your main stimulus. This is useful for providing extra instructions or reminders that apply to that specific trial. For example, you might use the stimulus to show a picture and the prompt to ask “What emotion is this person expressing?”

The timing parameters give you precise control over your experiment’s flow. The stimulus_duration parameter controls how long the main content stays visible. After this time, the content becomes invisible, but the buttons remain so participants can still respond. The trial_duration parameter sets a maximum time limit for the entire trial. That is, if participants don’t respond within this time, the trial ends automatically and their response is recorded as null (no response).

The response_ends_trial parameter is usually set to true, meaning that as soon as a participant clicks a button, the trial ends and the experiment moves on. You might set this to false if you want to show feedback after they respond but before moving to the next trial, or if you want to ensure participants see the stimulus for a minimum amount of time even if they respond quickly.

The newer version of this plugin includes more sophisticated layout controls. The button_layout parameter can be set to either ‘grid’ or ‘flex’, which are different ways of arranging your buttons on the screen. The ‘grid’ option (which is the default) lets you specify exactly how many rows and columns of buttons you want using the grid_rows and grid_columns parameters.

The enable_button_after parameter is useful when you want to prevent participants from responding too quickly. If you set this to 1000, for example, the buttons will be disabled for the first 1000 milliseconds (1 second) of the trial, forcing participants to look at the stimulus before they can respond.

10.3.1.2 Install

The installation is always the same for every plugin. Again, we can use a local or CDN method. We’re using the local method for this book.

Local method:

<script src="jspsych/plugin-html-button-response.js"></script>

Using the (online) CDN-hosted file:

<script src="https://unpkg.com/@jspsych/plugin-html-button-response@2.1.0"></script>

10.3.1.3 Examples

Here’s one of the examples they provide:

var trial = {
  type: jsPsychHtmlButtonResponse,
  stimulus: '<p style="font-size:48px; color:red;">GREEN</p>',
  choices: ['Red', 'Green', 'Blue'],
  prompt: "<p>What color is the ink?</p>"
};

This creates a trial that shows the question “Which color do you prefer?” with three buttons labeled “Red,” “Blue,” and “Green.” When a participant clicks any button, the trial ends and their response is recorded. The plugin automatically handles all the timing and data collection for you.

10.3.2 A Working Example

<!DOCTYPE html>
<html>
<head>
    <title>My experiment</title>
    <!-- Base JsPsych -->
    <script src="jspsych/jspsych.js"></script>
    <link href="jspsych/jspsych.css" rel="stylesheet" type="text/css" />
    
    <!-- Plugins -->
    <script src="jspsych/plugin-instructions.js"></script>
    
    <!-- custom CSS -->
    <link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<script src="exp.js"></script>
</body>
</html>
const jsPsych = initJsPsych();

// Create the timeline procedure
var quiz = {
    timeline: [
      {
        type: jsPsychHtmlButtonResponse,
        stimulus: jsPsych.timelineVariable('statement'),
        choices: ['True', 'False', 'I Dont Know'],
        post_trial_gap: 300
      }
    ],
    timeline_variables: [
    {
        statement: `<p>The human brain has more neurons than there are stars in the Milky Way galaxy.</p>`
    },
    {
        statement: `<p>Goldfish have a memory span of only 3 seconds.</p>`
    },
    {
        statement: `<p>We only use 10% of our brain capacity.</p>`
    },
    {
        statement: `<p>Humans share about 50% of their DNA with bananas.</p>`
    },
    {
        statement: `<p>Lightning never strikes the same place twice.</p>`
    }
  ],
  randomize_order: true
}

// Run the experiment
jsPsych.run([quiz]);
Live JsPsych Demo Click inside the demo to activate demo

10.3.3 Styling Buttons

We can customize our buttons in a few different ways. The first is to just change the style of all the buttons.

The button_html parameter actually takes a function that modifies the button HTML for each of the choice buttons.

I’ve created a new class called my-btn and added it to the <button> HTML. I’ve kept the original jspsych-btn class and just added the custom class to the end. This means that any CSS in jspsych-btn will carry over, but if there’s CSS in the custom class it will overwrite that CSS.

<!DOCTYPE html>
<html>
<head>
    <title>My experiment</title>
    <!-- Base JsPsych -->
    <script src="jspsych/jspsych.js"></script>
    <link href="jspsych/jspsych.css" rel="stylesheet" type="text/css" />
    
    <!-- Plugins -->
    <script src="jspsych/plugin-instructions.js"></script>
    
    <!-- custom CSS -->
    <link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<script src="exp.js"></script>
</body>
</html>
const jsPsych = initJsPsych();

// Create the timeline procedure
var styled_quiz_procedure = {
    timeline: [
      {
          type: jsPsychHtmlButtonResponse,
          stimulus: jsPsych.timelineVariable('statement'),
          choices: ['True', 'False', `I Don't Know`],
          post_trial_gap: 300,
          button_html: function(choice, choice_index) {
              return `<button class='jspsych-btn my-btn'>${choice}</button>`;
          }
      }
    ],
    timeline_variables: [
        {
            statement: `<p>The human brain has more neurons than there are stars in the Milky Way galaxy.</p>`
        },
        {
            statement: `<p>Goldfish have a memory span of only 3 seconds.</p>`
        },
        {
            statement: `<p>We only use 10% of our brain capacity.</p>`
        },
        {
            statement: `<p>Humans share about 50% of their DNA with bananas.</p>`
        },
        {
            statement: `<p>Lightning never strikes the same place twice.</p>`
        }
    ],
    randomize_order: true
}

// Run the experiment
jsPsych.run([styled_quiz_procedure]);
.my-btn {
  background-color: #6c757d;
  color: white;
  padding: 15px 25px;
  border: none;
  border-radius: 10px;
  margin: 8px;
  font-size: 16px;
  font-weight: bold;
  box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

.my-btn:hover {
  background-color: #5a6268;
}
Live JsPsych Demo Click inside the demo to activate demo

The second method is to customize each of the buttons according to what the button label (or choice) is.

Since this a function, we can add in our if-else logic to check what choice is, then change the style depending on the value. I’ll use a series of if-else statements to check and change the class.

For the CSS, I’ve created a base-btn class that contains all the CSS that is shared across the three buttons. Then I created separate classes for the red, green, and grey buttons.

<!DOCTYPE html>
<html>
<head>
    <title>My experiment</title>
    <!-- Base JsPsych -->
    <script src="jspsych/jspsych.js"></script>
    <link href="jspsych/jspsych.css" rel="stylesheet" type="text/css" />
    
    <!-- Plugins -->
    <script src="jspsych/plugin-instructions.js"></script>
    
    <!-- custom CSS -->
    <link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<script src="exp.js"></script>
</body>
</html>
const jsPsych = initJsPsych();

// Create the timeline procedure
var styled_quiz_procedure = {
    timeline: [
      {
          type: jsPsychHtmlButtonResponse,
          stimulus: jsPsych.timelineVariable('statement'),
          choices: ["True", "False", "I Don't Know"],
          post_trial_gap: 300,
          button_html: function(choice, choice_index) {
            if (choice === "True") {
                    return `<button class='jspsych-btn base-btn green-btn'>${choice}</button>`;
                } else if (choice === "False") {
                    return `<button class='jspsych-btn base-btn red-btn'>${choice}</button>`;
                } else if (choice === "I Don't Know") {
                    return `<button class='jspsych-btn base-btn gray-btn'>${choice}</button>`;
                }   
            }
      }
    ],
    timeline_variables: [
        {
            statement: `<p>The human brain has more neurons than there are stars in the Milky Way galaxy.</p>`
        },
        {
            statement: `<p>Goldfish have a memory span of only 3 seconds.</p>`
        },
        {
            statement: `<p>We only use 10% of our brain capacity.</p>`
        },
        {
            statement: `<p>Humans share about 50% of their DNA with bananas.</p>`
        },
        {
            statement: `<p>Lightning never strikes the same place twice.</p>`
        }
    ],
    randomize_order: true
    
}

// Run the experiment
jsPsych.run([styled_quiz_procedure]);
.base-btn {
    color: white;
    padding: 15px 25px;
    border: none;
    border-radius: 10px;
    margin: 8px;
    font-size: 16px;
    font-weight: bold;
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

.base-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 12px rgba(0,0,0,0.3);
}


.green-btn {
  background-color: #28a745;
}

.green-btn:hover {
  background-color: #218838;
}

.red-btn {
  background-color: #dc3545;
}

.red-btn:hover {
    background-color: #c82333;
}


.gray-btn {
  background-color: #6c757d;
}

.gray-btn:hover {
    background-color: #5a6268;
}
Live JsPsych Demo Click inside the demo to activate demo