Intersection Observers

Can someone tell me what I'm doing wrong here? I'm trying to get this IntersectinoObserver to update other elements than the one actually being observed, when the heading is scrolled into view, i want the corresponding element in the TOC to update and change some styles on it, but i can only get the observed element to change. is this some perf thing that wont let you do this? Source: https://github.com/t3-oss/create-t3-app/blob/38fd589c3c43e21eef19ec177e78192884b79d9e/www/src/components/navigation/tableOfContents.astro Demo: https://share.cleanshot.com/xddfsF
GitHub
create-t3-app/tableOfContents.astro at 38fd589c3c43e21eef19ec177e78...
Quickest way to start a new web app with full stack typesafety - create-t3-app/tableOfContents.astro at 38fd589c3c43e21eef19ec177e78192884b79d9e ยท t3-oss/create-t3-app
CleanShot Cloud
CleanShot 2022-09-18 at 20.10.45
GIF uploaded to CleanShot Cloud
83 Replies
julius
juliusOPโ€ข3y ago
Create T3 App
Environment Variables ๐Ÿš€ Create T3 App
Create T3 App is the quickest way to start a new web app with fullstack typesafety
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
Fwiw I've never had intersection observers work as expected They're...rough Is it possible that Tailwind isn't picking up the classes in the inline script?
julius
juliusOPโ€ข3y ago
julius
juliusOPโ€ข3y ago
im adding the same class to the entry and another item, but only the entry is being updated
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
Ah hrrrrm Another dumb question: Possible the document selector isn't selecting? I know astro loves to mangle ids and classnames
julius
juliusOPโ€ข3y ago
i've had console logs logging the element and it is correctly selected this file is even adding the correct classname but the dom is not updated
julius
juliusOPโ€ข3y ago
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
Oh??? fascinating hrm Possible that classname isn't compiled in?
julius
juliusOPโ€ข3y ago
perhaps... still don't know why this isn't wokring on both elements same class
Develliot
Develliotโ€ข3y ago
I've had a good experience using @react-hook/intersection-observer
julius
juliusOPโ€ข3y ago
im migrating off react
Develliot
Develliotโ€ข3y ago
Ah I just saw the code
julius
juliusOPโ€ข3y ago
GitHub
create-t3-app/TableOfContents.tsx at 10ebdda6dac2a0ff8d8f18482a8e72...
Quickest way to start a new web app with full stack typesafety - create-t3-app/TableOfContents.tsx at 10ebdda6dac2a0ff8d8f18482a8e72177e9610ad ยท t3-oss/create-t3-app
julius
juliusOPโ€ข3y ago
this was it before
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
More and more rethinking using Astro for this aeblobsweat2x
julius
juliusOPโ€ข3y ago
docusaurus has its quirks too but most defaults are good i suppose i could leave the ToC in react if it doesnt work too
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
This confused me enough to dig in - bg styles are applied but overridden
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
So that is working
julius
juliusOPโ€ข3y ago
maybe the script is running at the wrong time ๐Ÿค” so that other styles are applied after...
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
How are the page styles applied? I'm guessing they're "later" in the CSS order
julius
juliusOPโ€ข3y ago
its tailwind but the observer should add/remove later so shouldn't that take precedense?
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
Here's the hierarchy that the CSS has
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
So I'm doubling down on my guess that the element select is bad for the TOC bit
julius
juliusOPโ€ข3y ago
yea last commit i tested this and it updates the dom
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
Can you console log tocItem to see if it exists?
julius
juliusOPโ€ข3y ago
julius
juliusOPโ€ข3y ago
Create T3 App
Environment Variables ๐Ÿš€ Create T3 App
Create T3 App is the quickest way to start a new web app with fullstack typesafety
julius
juliusOPโ€ข3y ago
some edgecases it doesnt select but should work for the most
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
The dark and hover styles aren't in the css bundle @julius Wait maybe they are hmm
julius
juliusOPโ€ข3y ago
can i jsut add a dummy element with hidden and those styles then
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
I'd try this
julius
juliusOPโ€ข3y ago
but why isn't the text-error applied, or is it overridden?
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
Huh yeah it isn't applying auowhraiuwherawer; this sucks grr
julius
juliusOPโ€ข3y ago
wonder if this is an astro quirk or a tailwind one
Develliot
Develliotโ€ข3y ago
Is the order of styles in the outputted html different to the order of class names
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
I think adding and removing tailwind classes is...sketch for this tbh React and other "js owning html" solutions are much cleaner Hurts to say but...might be better to make two CSS classes for the different treatments? ๐Ÿ˜…
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
Is it possible the else clause here is running erroneously?
Develliot
Develliotโ€ข3y ago
It doesn't look "inline" the styles must live somewhere else
julius
juliusOPโ€ข3y ago
commented the else and still same wdym?
theo (t3.gg)
theo (t3.gg)โ€ข3y ago
I give up, observers are cursed
julius
juliusOPโ€ข3y ago
is it possible the ToC isn't created when the observer is created? it should be though, it should be rendered on the server and the script is clientside
Unknown User
Unknown Userโ€ข3y ago
Message Not Public
Sign In & Join Server To View
julius
juliusOPโ€ข3y ago
wtf
julius
juliusOPโ€ข3y ago
when i log this it says the class is there, but it's not in the dom tree
julius
juliusOPโ€ข3y ago
even though the id is the same
julius
juliusOPโ€ข3y ago
Develliot
Develliotโ€ข3y ago
What if you separated the on intention handler and the new intersection instance into different functions
julius
juliusOPโ€ข3y ago
i had that before and then it complained that they were previously defined or smth
Develliot
Develliotโ€ข3y ago
I'm only saying that Incase it's getting a ref to something that has re rendered
julius
juliusOPโ€ข3y ago
<script is:inline>
// Toggle classes when items are in view
const observerHandler = (entries) => {
for (const entry of entries) {
const heading = entry.target; // observed item
const tocItem = document.querySelector("#toc-example"); // corresponding item in TOC

console.log(tocItem);

document.querySelector("html").classList.add("bg-error");
document.querySelector("html").classList.add("light");
document.querySelector("html").classList.remove("dark");

tocItem.classList.toggle("text-error");

tocItem.style.textDecoration = "underline";

if (entry.isIntersecting) {
// this works
heading.classList.add("text-error");

// test: this doesn't
tocItem?.classList.add("text-error");

// this what i actually want to do
tocItem?.classList.add(
"underline",
"text-t3-purple-700",
"dark:text-t3-purple-100",
);
} else {
// again, this works
heading.classList.remove("text-error");

// this doesn't
tocItem?.classList.remove("text-error");

// this is what i actually want to do
tocItem?.classList.remove(
"underline",
"text-t3-purple-700",
"dark:text-t3-purple-100",
);
}
}
};

const observerOptions = {
rootMargin: "-100px 0% -66%",
threshold: 1,
};

const observer = new IntersectionObserver(observerHandler, observerOptions);

document.querySelectorAll("article :is(h1,h2,h3)").forEach((h) => {
observer.observe(h);
});
</script>
<script is:inline>
// Toggle classes when items are in view
const observerHandler = (entries) => {
for (const entry of entries) {
const heading = entry.target; // observed item
const tocItem = document.querySelector("#toc-example"); // corresponding item in TOC

console.log(tocItem);

document.querySelector("html").classList.add("bg-error");
document.querySelector("html").classList.add("light");
document.querySelector("html").classList.remove("dark");

tocItem.classList.toggle("text-error");

tocItem.style.textDecoration = "underline";

if (entry.isIntersecting) {
// this works
heading.classList.add("text-error");

// test: this doesn't
tocItem?.classList.add("text-error");

// this what i actually want to do
tocItem?.classList.add(
"underline",
"text-t3-purple-700",
"dark:text-t3-purple-100",
);
} else {
// again, this works
heading.classList.remove("text-error");

// this doesn't
tocItem?.classList.remove("text-error");

// this is what i actually want to do
tocItem?.classList.remove(
"underline",
"text-t3-purple-700",
"dark:text-t3-purple-100",
);
}
}
};

const observerOptions = {
rootMargin: "-100px 0% -66%",
threshold: 1,
};

const observer = new IntersectionObserver(observerHandler, observerOptions);

document.querySelectorAll("article :is(h1,h2,h3)").forEach((h) => {
observer.observe(h);
});
</script>
thia?
julius
juliusOPโ€ข3y ago
now it says this so maybe smth's wrong with execution-order
Develliot
Develliotโ€ข3y ago
You haven't set a root element in the observer options But you are setting targets with observer.observe I would possibly revert to what it was before that error and try and set the root element and see if that makes a difference You defo want to set an intersectional observer once not in a loop. You want to set the root component in the options and you want observer.observe all the child elements in a loop
julius
juliusOPโ€ข3y ago
like that?
Develliot
Develliotโ€ข3y ago
You have a div of the articles that is your root give that an id and get element by id Set that to be your intersection observer not in the loop, just at the top of the in line script
julius
juliusOPโ€ข3y ago
but the toc is not in that article
Develliot
Develliotโ€ข3y ago
Is this some title colour changing when you stroll past articles that match the title
julius
juliusOPโ€ข3y ago
yea thats just for test i only want to change the toc items when the headings on the article is in view
julius
juliusOPโ€ข3y ago
this what i want
Develliot
Develliotโ€ข3y ago
Ok but the thing you are observing is the article appearing in the article wrapper. But you want this code to work in the TOC component
julius
juliusOPโ€ข3y ago
so im observing the article, but want to change it's corresponding item in the TOC
Develliot
Develliotโ€ข3y ago
I can't figure out what root would be in this scenario it's what ever has the fixed height and causes the article to overflow hidden The articles are defo the targets Document element might be it might be window
ZiiM
ZiiMโ€ข3y ago
So I was messing around with your code and got a was able to get a slightly different result in whic all headers are now being colored when scrolled into view and color removed when scrolled out. I dont think thats exactly the result your looking for, I assume you just want the newest to be red.
Develliot
Develliotโ€ข3y ago
I should probably have a play with the code too
julius
juliusOPโ€ข3y ago
the pushed code is slightly modified and doing some tests
Develliot
Develliotโ€ข3y ago
It's quite hard doing this from a phone ๐Ÿ˜…
julius
juliusOPโ€ข3y ago
yea i could imagine
julius
juliusOPโ€ข3y ago
GitHub
create-t3-app/TableOfContents.tsx at main ยท t3-oss/create-t3-app
Quickest way to start a new web app with full stack typesafety - create-t3-app/TableOfContents.tsx at main ยท t3-oss/create-t3-app
julius
juliusOPโ€ข3y ago
what i cant figure out is why i can change some elements' classes but not some the only thing i can think of is the tocItem it selects isn't whats in the dom, but dont know why that would be the case
julius
juliusOPโ€ข3y ago
found the issue
julius
juliusOPโ€ข3y ago
grrr forgot we're rendering this component in two places ffs so querySelector selected the other element haha why am i not getting errors that i have multiple items with same id then
Develliot
Develliotโ€ข3y ago
Can you see it changing the other component
julius
juliusOPโ€ข3y ago
that component is only on mobile so hard to debug that one xd
julius
juliusOPโ€ข3y ago
i'll remove id and select like this i guess
Develliot
Develliotโ€ข3y ago
Astro should warn about that I think you might have found a bug
julius
juliusOPโ€ข3y ago
i'll let them know
Develliot
Develliotโ€ข3y ago
I thought chrome dev tools would pick that up too Possibly not
julius
juliusOPโ€ข3y ago
CleanShot Cloud
CleanShot 2022-09-18 at 22.03.47
GIF uploaded to CleanShot Cloud
Develliot
Develliotโ€ข3y ago
Nice one
julius
juliusOPโ€ข3y ago
is this smelly or ok
Develliot
Develliotโ€ข3y ago
It's terse I'll give you that. It's a shame that string literals aren't an option. My main issue is I'm not sure I like different components being able to class swap from other components what happens if it gets added twice from different places then remove once, hard to keep track off.
julius
juliusOPโ€ข3y ago
well the script is in the TOC, and toggles classes for the TOC so that's fine i think
Develliot
Develliotโ€ข3y ago
Very true Unless you have that component twice ๐Ÿ˜…
Want results from more Discord servers?
Add your server