Character Vault
Any Concept / Any System
Your System Come To Life
Roll20 for Android
Streamlined for your Tablet
Roll20 for iPad
Streamlined for your Tablet

Personal tools


From Roll20 Wiki

Jump to: navigation, search

Now on Dev Server: jQuery for character sheets! - source


We’ve been working hard to try to make character sheet development more approachable for new sheet authors. Specifically, we’d like to give sheet authors more direct access to the sheet’s HTML elements without having to rely so much on CSS trickery. To this end, we’re exposing some jQuery functionality to sheet workers. For this first iteration, we’re implementing the .on(), .addClass(), .removeClass(), and .toggleClass() functions.

Please note that because of the limitations of how character sheet JavaScript works, there are some significant differences between this implementation of jQuery and the full jQuery library. To emphasize these differences and attempt to reduce confusion, these functions will be called with $20, as opposed to the traditional jQuery $, example:

$20('button.attack').on('mouseenter', (event) => {
    const selector = `#${}`;

Note that all selectors for these functions will be automatically scoped to the character sheet.


The jQuery functions as they are currently implemented have several limitations:

  • The contents of individual repeating items can't be targeted or reacted to
  • jQuery occasionally goes unresponsive after uploading new code to the sandbox
  • change event has no relation to actual attribute change as it fires as a true "change" event instead of the database change event that other sheetworker listeners fire off of.
  • None of the $20 functions are directly tied to a character’s data, these changes won’t automatically carry over if the sheet is closed and then re-opened. It is the sheet author’s responsibility to save something in the character’s data and implement an sheet:opened event to get back to the desired state when the sheet is opened.


$20(<selector>).on(<event>, <callback (eventinfo)>)

Adds an event handler <callback> to be triggered when the given <event> occurs on elements matching the CSS <selector>

  • event: we’re currently supporting the following events: change, click, hover, mouseenter, mouseleave. We may be able to expand this list in the future.

  • callback (eventinfo): Because of limitations to how a sheet’s JavaScript is executed, we’re unable to return the full eventinfo object that you’d normally expect from jQuery, nor will this in the context of the callback refer to the triggering element. Instead, the callback function will receive the following object:
    // This will include all html attributes of the element that triggered the event,
    // as well as the name of the tag itself
    "htmlAttributes": {
        "class": "green", 
        "id": "test",
        "data-test": "something",
        "tagName": "h4"
    // Whether alt, shift or ctrl keys were down when the event was triggered
    "altKey": false,
    "shiftKey": false,
    "ctrlKey": false,
    // Page coordinates of the triggering event
    "pageX": 70,
    "pageY": 528

Adds the specified <class> to the elements matching the <selector>, unless the class is already present on the element.


Removes the specified <class> from the elements matching the <selector>, does nothing if the given element does not already have this class.


Adds the specified <class> to the elements matching the <selector> if the elements do not already have the given class, removes the class if it is already present on the given element.


Adding or Removing a class. Useful for hiding things.


<div class="header">
    <div class="tab-button active" data-tab="core">Core</div>
    <div class="tab-button" data-tab="spells">Spells</div>
    <div class="tab-button" data-tab="bio">Bio</div>
    <div class="tab-button" data-tab="settings">Settings</div>
<div class="body">
    <div class="tab-container active" data-tab="core">This is the Core tab!</div>
    <div class="tab-container" data-tab="spells">This is the Spells tab!</div>
    <div class="tab-container" data-tab="bio">This is the Bio tab!</div>
    <div class="tab-container" data-tab="settings">This is the Settings tab!</div>

<script type="text/worker">
    $20('.header .tab-button').on('click', (e) => {
        const tab = e.htmlAttributes['data-tab'];


.header .tab-button {
    display: inline-block;
    width: 20%;
    padding: .5em .5em .25em .85em;
    background-color: gray;
    border-radius: 1em 1em 0 0;
    font-size: 1.5em;
    border: 1px solid black;
    margin-right: -4px;

.header {
    background-color: white;
    font-weight: bold;
    border-bottom: none;

.body .tab-container {
    display: none;
    padding: 2em;
    box-sizing: border-box;
    width: 100%;
    height: 300px;
    font-size: 1.2em;

.body {
    display: block;

Modifier keys to modify a roll:

<p>Click for a normal (public) roll. Hold down the <code>alt</code> key and click to whisper the roll to the gm.</p>
<button class="roll">1d20</button>

<script type="text/worker">
    $20('button.roll').on('click', async (e) => {
        const roll = e.altKey ? '/w gm [[1d20]]' : '[[1d20]]';
        const results = await startRoll(roll);

Sheets Using jQuery


Mod scripts can access some jQuery as part of Mod Update 2024.

Suggestions to expand jQuery

Related Pages