[Userscript] Vertical Reviews

thought it was something to do with the wk update…another script had broken and was updated… I’ll test on this end more…

hi, great script, always helpful!

could you update it to show in vertical mode in the new extra study mode?

Good idea. I’ve updated the script for this. v2.0.1 now supports extra study mode.


Never seen this script before! Great idea & can’t believe I never thought of that…

@lon this script is great, but the “vertical for short words” and “vertical for random short words” settings don’t seem to work with Reorder Omega enabled (only “always show vertically” works) - might it be an easy fix by you or Kumirei?
If not, no worries! :slight_smile:

Also @Kumirei, when this script is set to “always show vertically”, the Omega “Preset” text gets goes vertical as well, might that have a quick fix?


I’ll have a look at it tomorrow maybe


I imagine the text going vertical is because I apply a style rule tat everything in that part of the webpage needs to go vertical. That’s probably easy to fix.

I would need to investigate why it’s not working with the other options for short words. I don’t use that script, so I can’t guess what would be causing it. Maybe if the script is adding extra words, like I see in the screenshot, I’m counting the length of the word wrong so it never finds a “short” one.

1 Like

@Kumirei sorry for tagging you about this, all fixed so you don’t need to check anything in the end!

@lon Yep, you were right!
I modified the text-orientation CSS to only apply to the span inside the character id instead of anything in it so that it’ll only make the actual word vertical, and also changed the short() function to only take into account letters in that span. I also made it always take up 3 letters of height if vertical so that it’ll jump around a bit less!

Here’s the modified code just in case you want to update the script at some point (I don’t think I’ve broken anything, all seems to still be working :slight_smile:)

Modified code
// ==UserScript==
// @name        WaniKani Vertical
// @version     2.0.2
// @description Display WaniKani reviews with vertical text
// @author      @lonmcgregor
// @copyright   2021, lonm
// @license     MIT
// @namespace   lonm
// @homepageURL https://gist.github.com/LonMcGregor/972f523e601661475fd0600843f8fb55
// @include     https://www.wanikani.com/review/session
// @include     https://www.wanikani.com/extra_study/session*
// ==/UserScript==

function showControls(){
    // Choose between modes
    // Always = show all words vertically
    // Short = Show all short words vertically
    // Random = For short words, offer a 1:2 chance of showing them vertically
    const selector = document.createElement("select");
    selector.id = "lonm-verticaltextmod";
    selector.innerHTML = `<optgroup label="Controls for Vertical Text">
    <option value="always">Always show all reviews vertically</option>
    <option value="short">Show short reviews vertically</option>
    <option value="random">Show random short reviews vertically</option>
    selector.value = getSavedMode();
    selector.addEventListener("input", setSavedMode);

function getSavedMode(){
    // get the saved value. if its not set, default to random
    const storedvalue = localStorage.getItem("lonm-verticaltextmod");
    return storedvalue ? storedvalue : "random";

function setSavedMode(){
    // save the mode and update the page
    const storedvalue = document.querySelector("#lonm-verticaltextmod").value;
    localStorage.setItem("lonm-verticaltextmod", storedvalue);
    if(storedvalue === "always"){
    } else {

function addCss(){
    // Add custom css to the page to support the mod
    const alwaysvertical = `/* for the main page */
    .lonm-alwaysvertical #character {
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 1;
        float: right;
        width: 400px;
        height: 100vh !important;
    .lonm-alwaysvertical #character span {
        writing-mode: vertical-rl;
        text-orientation: upright;

    .lonm-alwaysvertical #information {
        width: calc(100% - 460px);

    .lonm-alwaysvertical #additional-content ul li {
        width: 15%;

    /* for the settings box */
    .lonm-alwaysvertical #reviews footer {
        position: fixed;
        bottom: 0;
        right: unset;
        left: 10px;
        z-index: 0;

    .lonm-alwaysvertical #reviews footer {
        position: fixed;
        bottom: 0;
        right: unset;
        left: 10px;
        z-index: 0;

    footer #lonm-verticaltextmod {
        background-color: #e1e1e1;
        border: none;
        color: #888888;
        width: 40px;
        height: 33px;
        margin-left: 10px;
        border-radius: 3px 3px 0 0;

    footer #lonm-verticaltextmod:focus {
        background-color: unset;
        color: unset;

    /* for random chances */
    body:not(.lonm-alwaysvertical) #character.vocabulary.vertical span {
        writing-mode: vertical-rl;
        text-orientation: upright;
        width: 100%;
        height: 3em;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 12px 0 10px 0;

	/* for extra reviews, to make the title not overlap */
	div#menu-bar-title {
		text-align: left;
		padding-left: 60px;
    const style = document.createElement("style");
    const tn = document.createTextNode(alwaysvertical);

function short(){
    // 3 characters or shorter word
    return document.querySelector("#character").querySelector('span').innerText.length <= 3;

function random(){
    // either we always want it true for short words, or a 1:2 random chance
    return getSavedMode() === "short" | Math.random() <= 0.5;

function chooseOrientation(){
    // When not always on, handle choosing whether to show it or not
    if(short() && random()){
    } else {

// Observe when going to next review item
const VerticalTextMutationObserver = new MutationObserver(chooseOrientation);

function init(){
    if(document.querySelector("#loading") && document.querySelector("#loading").style.display === 'none'){
        VerticalTextMutationObserver.observe(document.querySelector("#character").querySelector('span'), {childList: true, subtree: true, characterData: true});
    } else {
        setTimeout(init, 150);

setTimeout(init, 500);

Thanks for the help!

1 Like

Thanks. Fixes look good, so I merged them into the main script.