List Item Hover Effect - possible?

Hello all, I’m trying to add a hover effect on an unordered list (wikitext) such that the line you’re hovering over gets a yellow background. When nesting is involved, this fails due to how the HTML is generated, is there a CSS solution that will work?

Meaning when applying just to li:hover and hovering over “Line B1” I want this:
image

But it instead does this:
image

If I write the html directly like here in the below (3rd chunk) then it works, but ideally I could keep using wikitext. Ideas?

<style>
.mylist ul li:hover { background-color:yellow; }
</style>

<div class="mylist">

<!-- Wikitext -->

* Line A
* Line B
** Line B1
* Line C

<!-- Converts to -->

<ul>
  <li>Line A</li>
  <li>Line B
    <ul>
      <li>Line B1</li>
    </ul>
  </li>
  <li>Line C</li>
</ul>

<!-- Instead of this (which would work) -->

<ul>
  <li>Line A</li>
  <li>Line B</li>
  <ul>
    <li>Line B1</li>
  </ul>
  <li>Line C</li>
</ul>

</div>

That’s a tricky one. Used an LLM for brainstorming :wink:

TW creates UL and OL lists according to the HTML spec. Have a closer look at: <ul>: The Unordered List element - HTML | MDN where it says:

Permitted content: LI, SCRIPT and TEMPLATE.

So your second example would be invalid HTML code.


The best with a background highlight, I can do with CSS only and no extra HTML elements, like SPANS, is as follows.

  • The bullet points have to be “none”. Otherwise they will go away on hover
    • list-style-type: none … If you remove this one, you will see what I mean
  • If a subitem is hovered, it also highlights the “parent” list element
    • I personally like the “breadcrumbs” vibe
<style>
/* highlight only the text line on hover */
.tc-tiddler-frame li {
  list-style-type: none;
}
.tc-tiddler-frame li:hover {
  background: none; /* prevent full box fill */
}

.tc-tiddler-frame li:hover {
  background: yellow;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone; /* Safari/Chrome */
  display: inline; /* makes background hug text only */
}
</style>

* First list item
* Second list item
** A subitem
** A subitem
* Third list item

The whole thing is a bit of a hack.



Underline instead of highlight. – IMO looks better. – Still a bit hacky.

<style>
.tc-tiddler-frame li {
  position: relative;           /* needed for absolute pseudo */
}

/* highlight strip */
.tc-tiddler-frame li:hover::before {
  content: "";                  /* empty box */
  position: absolute;
  left: 0;                      /* align with text start */
  top: calc(1em + 3px);
  height: 2px;                  /* underline height */
  width: calc(100% - 1em);      /* adjust for bullet width */
  background: green;
}
</style>

* First list item
* Second list item
** A subitem
** A subitem
* Third list item

1 Like

CSS’s :has can be your friend here. This version does what I think you want:

<style>
.mylist li:hover { 
  background-color: yellow; 
  &:has(li:hover), ul {background-color: white;}
}
</style>

<div class="mylist">

* Line A
* Line B
** Line B1
** Line B2
* Line C
** Line C1
*** Line C1.1
*** Line C1.2
**** Line C1.2.1
**** Line C1.2.2
**** Line C1.2.3
** Line C2

</div>

output2

has is relatively recent to Firefox (version 121, December 2023) but has been in other major browsers somewhat longer.

I would love to replace background-color: white; with background-color: revert or some such, but it doesn’t work, and I don’t have time right now to figure out why.

If the nested CSS seems dense, here’s an equivalent non-nested version:

.mylist2 li:hover { background-color:yellow;}
.mylist2 li:hover:has(li:hover) {background-color: white;}
.mylist2 li:hover ul {background-color: white;}
4 Likes

That’s really clever Scott - thanks - works great!

I wonder if we could ever use this approach to click to create a tiddler title based on the highlight? Idealy replacing it with a link.

  • Perhgaps each line item needs tiddlywiki script?

If I’m understanding you correctly, the discussion and my post here may be relevant to your question. There I used td elements but here you’d use li elements.

1 Like

Do I understand you @stobot ?

  • Thanks this gives me something to work with.

So rather than in your example, where the number is the text, the text would be the li items, and I could put a click action (via the eventCatcher) to capture that text?

SSo I would need to alter $value={{{ [<now "0hh:0mm:0ss.0XXX">addprefix[ at ]addprefix<dom-xxxxx-id>] }}} in xxxxx-click ?

  • But how do we get the text?

As I read dom-xxxxx-id is automatically created and you can use it as a variable? That is you can extract from the dom Document Object Model a value from the html and use an action to store it?

  • This seems vary powerful, as one could import html content, then using an event catcher, select parts and save to tiddlers/fields
  • The next trick is to see how we may cut away the text (if it exists in the tiddler) and remove it. In my use case to remove a selected bullet point, potentialy replacing it, or just saving elsewhere and deleting.

A caution here. I may be missing it, but I don’t see a way in the EventCatcher documentation to get at the text of the DOM node, nor at the node itself. And even if you did, for anything but leaf nodes of the tree, that text would include all the child branches, so you would further need to extract the relevant title yourself.

What this means is that you would probably have to extend the tree-generating code to add an additional attribute to your list items, perhaps title, which is meaningful on its own and which you could then access as dom-title. This sounds reasonable if you’re already writing custom tree-generation wikitext. But if you’re using, say, the already-complex TOC macros, then this will be much harder.

This is where the EventCatcher API is much trickier to use than the native JS version. I don’t know that there is anything to do about this. TW very intentionally limits our access to the DOM. But I get frustrated not being able to do something like this:

On the main page, open the developer’s console (CTRL-SHIFT-J or CMD-SHIFT-J) and enter this:

[...document.querySelectorAll('.tc-table-of-contents')][0].addEventListener('mouseover', (evt) => {
    if (evt.target.classList.contains('tc-toc-caption')) {
        console.log(`hovering on "${evt.target.textContent}"`)
    }
})

Then fiddle with the main sidebar TOC, and watch the various titles being logged in the console.

Is there a TW equivalent?

Thanks for the warning. yes it does look to be a bit of witch craft. in the example @stobot Adam linked to it only seems to be a matter of referring to a variable with the prefix dom- to the html ID.

  • but as you imply the id needs to be there in the first place, adding complexity. I wonder if in the absence of a hard coded ID CSS creates one?

This suit of issues seem to touch on an area of my interest which is exposing access to more CSS and html native functionally as for example the event catcher widget does. I don’t want to subvert tiddlywiki widgets just have a few open to accessing the intelligence in internet technology standards. Not that I am much more than a script kiddy in this space.

  • to me read only access to the Dom should be fine, allowing us to capture the result in a variable or reference. keeping in mind this Dom can be a product of imported html that now lives in a tiddler or that generated in the render process.