Allow CSS styling based on card state

In the same way the nightMode css class is added to element when night mode is set, and win/mac/linux/mobile/etc css class is added dependent on the platform, it would be nice to have some kind of new/learning/relearning/etc css class added if the card is in any of those states.

Alternatively, a better solution might be to allow this indirectly by adding a {{State}} special field which evaluates to the card state (say New/Learning/Relearning/etc) and using it as a css class like <div class="{{State}}> within the card html editor.

I’m not overly familiar with the Anki codebase, but I assume this would be a relatively easy feature to implement and with very little maintenance cost.

An example use case: when using the “Mix new cards and reviews” option and going through a deck whose contents you haven’t seen before, it can be helpful to get an instant visual cue that the you’re seeing a new card for the first time, say by changing the background color of the card. This is helpful especially to those who intentionally hide the new/learning/relearning counts at the bottom.

Edit: If this feature seems compatible with the Anki project goals but is low-priority, I’d also appreciate confirmation of this as I may try to implement it myself and submit a pull request. Any tips as to how to implement it to someone currently unfamiliar with the Anki codebase would be helpful as well.

You could probably already accomplish this with The 2021 scheduler - Frequently Asked Questions

I hope it’s ok to revive this—I just spent a few hours writing an extensive post asking for this exact feature, specifically in order to distinguish new cards from other types of cards, both on desktop and mobile. Right before I posted it, I decided to search the forums to see if someone else had asked for it, and found Dae’s solution here. OP probably doesn’t need this, but if someone else is looking for a solution and you don’t really know any javascript, here’s something basic to get you started:

In the “Custom scheduling” section at the bottom of the deck options menu (edit: use Edit 5 instead):

if (states.current.normal?.new) {
const new_tag = document.createElement("style");
new_tag.innerHTML = ".notifier::before {content: 'NEW!  '; color: blue; font-size: 60%; white-space: pre;}";
document.body.appendChild(new_tag);
}

On the card template:

<div class="notifier">{{Your Field Here}}</div>

All the javascript is doing is adding a <style> element to new cards, so you can customize the line new_tag.innerHTML = "..."; with CSS accordingly (say, if you wanted to change the card’s background color instead: new_tag.innerHTML = ".card {background-color: blue;}";). Note that the tag won’t appear in preview, but it works when you actually see the card during review.

I am not a programmer, so there is probably a better way to write this particular solution—but hopefully, this will give someone with even less coding experience than me a good place to start.

ETA: Unfortunately, this isn’t working completely as I expected; at least on Anki mobile, cards are still marked as “new” after already being rated “again” for the first time. I do think OP’s original suggestion would be very helpful to people who don’t know how to code—the CSS is a lot easier to figure out on your own than the javascript.

(A bunch of trial and error attempts)

Edit 2: Ugh, doesn’t work at all if new cards come first. Will try to fix.

Edit 3: A bit of brute force, but probably the best I will be able to do. Pro is, if you wanted to customize every card type, there you go. I’m worried about it slowing down Anki throughout a full review session, but will have to wait to test.

if (states.current.normal?.new) {
const new_tag = document.createElement("style");
new_tag.innerHTML = ".notifier::before {content: 'NEW!  '; color: blue; font-size: 60%; white-space: pre;}";
document.body.appendChild(new_tag);
}
if (states.current.normal?.learning) {
const learning_tag = document.createElement("style");
learning_tag.innerHTML = ".notifier::before {content: '';}";
document.body.appendChild(learning_tag);
}
if (states.current.normal?.review) {
const review_tag = document.createElement("style");
review_tag.innerHTML = ".notifier::before {content: '';}";
document.body.appendChild(review_tag);
}
if (states.current.normal?.relearning) {
const relearning_tag = document.createElement("style");
relearning_tag.innerHTML = ".notifier::before {content: '';}";
document.body.appendChild(relearning_tag);
}

Edit 4: A probably better alternative to the above, but not working on the backs of cards. Not really an issue for me, so I might stop here.

Custom scheduling:

if (states.current.normal?.new) {
document.getElementById("notification").classList.add("notifier");
}

Card template:

<div id="notification">{{Your Field}}</div>

Styling:

.notifier::before {
content: "NEW!  ";
color: blue;
font-size: 60%;
white-space: pre;
}

Edit 5: Haven’t tested this extensively, but I think it’s the best version so far.

Custom scheduling:

if (document.getElementById("notification") == null) {
const notification = document.createElement("style");
notification.setAttribute("id", "notification");
document.body.appendChild(notification);
}

if (states.current.normal?.new) {
document.getElementById("notification").innerHTML = ".notifier::before {content: 'NEW!  '; color: blue; font-size: 60%; white-space: pre;}";
}
if (states.current.normal?.review) {
document.getElementById("notification").innerHTML = "";
}
if (states.current.normal?.learning) {
document.getElementById("notification").innerHTML = "";
}
if (states.current.normal?.relearning) {
document.getElementById("notification").innerHTML = "";
}

Card template:

<div class="notifier">{{Your Field}}</div>
3 Likes

I’m just going to list what I’ve learned from reading the above:

  1. The “Custom scheduling” javascript is a monkey patch, while it runs the states object exists, but states is not accessible from the normal card design.
  2. If we want to expose states, it can be injected directly into the HTML. (shown later)
  3. I’m assuming states is not exposed on purpose to avoid API surface increase.

Custom scheduling:

// expose states
e = document.createElement("script")
e.text='var states='+JSON.stringify(states)
document.body.appendChild(e)

// add ankiState_* to body class, e.g. ankiState_new
ankiState = Object.keys(states.current.normal).shift()
document.body.classList.add('ankiState_'+ankiState)

Card template styling (untested):

body.ankiState_new .notifier::before {
  content: 'NEW!  ';
  color: blue;
  font-size: 60%;
  white-space: pre;
}