Next,js 14 , Tailwind CSS and scrollbars
Unanswered
American Bobtail posted this in #help-forum
American BobtailOP
Sorry for the double post. But I'm trying to frame this as a theoretical question to see if I can get an answer.
I am using the classic approach to use the context API to provide the Theming to the entire app. The theme provider component wraps the { children } in the root
From my experiments, any styling of the scrollbar must occur here. Trying to do so in the home page, for example, does not work. This may be because under the hood this is a Single Page Application (SPA).
This poses a conundrum. Because I cannot use context in
So I'm stuck with a light scrollbar in a darktheme or vice versa.
Any suggestions?
Any help would be greatly appreciated.
Cheers!
I am using the classic approach to use the context API to provide the Theming to the entire app. The theme provider component wraps the { children } in the root
layout.tsx so that the entire app can have access to it. From my experiments, any styling of the scrollbar must occur here. Trying to do so in the home page, for example, does not work. This may be because under the hood this is a Single Page Application (SPA).
This poses a conundrum. Because I cannot use context in
layout.tsx since it's the root component where the context provider is wrapping everything, it would seem I have no way to conditionally style the scrollbar depending on whether the theme is set to dark or light.So I'm stuck with a light scrollbar in a darktheme or vice versa.
Any suggestions?
Any help would be greatly appreciated.
Cheers!
73 Replies
Gray-tailed Tattler
Why can't you just style the scrollbars from some global css? That break your ability to toggle themes for the scrollbar? Maybe create a side effect to your existing toggling logic to add a theme class to <body> or <html> and toggle scrollbar theme that way.
Css gives built-in web kit scrollbar and scrollbar to provide styles
@Gray-tailed Tattler Why can't you just style the scrollbars from some global css? That break your ability to toggle themes for the scrollbar? Maybe create a side effect to your existing toggling logic to add a theme class to <body> or <html> and toggle scrollbar theme that way.
American BobtailOP
Thnaks for he reply.
I have a theme-switch whcih toggles a context variable , also a state variable, so that when the user clicks , a re-render is triggered. I can't do that in CSS. This kind of interactivity requires REact's context API, right?
But I will think abiout adding a class to body. I was always told that directly maniopulating the DOM goes against React's etiquette, but maybe there's no other way.
Again thanks!
I have a theme-switch whcih toggles a context variable , also a state variable, so that when the user clicks , a re-render is triggered. I can't do that in CSS. This kind of interactivity requires REact's context API, right?
But I will think abiout adding a class to body. I was always told that directly maniopulating the DOM goes against React's etiquette, but maybe there's no other way.
Again thanks!
@<Milind ツ /> Css gives built-in web kit scrollbar and scrollbar to provide styles
American BobtailOP
Hi, thanks. Yes, at first I was doing just that. But then I wanted to style them conditionally, according to Theme. There's a Tailwind CSS plug in, called Tailwind Scrollbar, which adds those classes and they can be coupled with "datk:". The issue , in short, is that I can only seem to be able to style the scrollbar in Layout,tsx, but since Layout.tsx is the highest compoenent and context provider, I cannot access the context to conditionally style the scrollbar acccording to theme.
There must be a way.
There must be a way.
Gray-tailed Tattler
Ya direct dom manipulation is discouraged. What about creating context in your layout without the HOC
‘’’
import React, { createContext } from 'react';
// Create a Context object
const MyContext = createContext();
// Define your layout component
const Layout = ({ children }) => {
const contextValue = { /* ... your context value here / };
return (
<MyContext.Provider value={contextValue}>
{children}
</MyContext.Provider>
);
};
// Use the Layout component to wrap your application
const App = () => (
<Layout>
{/ Rest of your application */}
</Layout>
);
export default App;
‘’’
‘’’
import React, { createContext } from 'react';
// Create a Context object
const MyContext = createContext();
// Define your layout component
const Layout = ({ children }) => {
const contextValue = { /* ... your context value here / };
return (
<MyContext.Provider value={contextValue}>
{children}
</MyContext.Provider>
);
};
// Use the Layout component to wrap your application
const App = () => (
<Layout>
{/ Rest of your application */}
</Layout>
);
export default App;
‘’’
You can do so without context. When you change a theme, add an attribute to html like theme=dark
And in css, when html.dark is true, apple dark scrollbar
Else light scrollbar
You could make use of next-themes package for seemless switching. It uses context under the hood and local storage to save theme value
Also adds html attribute like i said before
@Gray-tailed Tattler Ya direct dom manipulation is discouraged. What about creating context in your layout without the HOC
‘’’
import React, { createContext } from 'react';
// Create a Context object
const MyContext = createContext();
// Define your layout component
const Layout = ({ children }) => {
const contextValue = { /* ... your context value here */ };
return (
<MyContext.Provider value={contextValue}>
{children}
</MyContext.Provider>
);
};
// Use the Layout component to wrap your application
const App = () => (
<Layout>
{/* Rest of your application */}
</Layout>
);
export default App;
‘’’
American BobtailOP
You just gave me an idea!
For "dark:" variants to work on any element, Tailwind requires the parent element to have the class "dark". So if the HTML elelemnt, the highest ellemnt, jas teh class "dark" any children with variant "dark:" will get the styling. That would simplify everything immensely, because I coudl get rid of Context altogether, and just have the theme-swicth apply the class "dark" to the HTML element or remove it.
Am I getting this right?
And because I don't have to use conetxt, not eveythig woild be a client component, and I could have server compoenents back!
This si exciting!
For "dark:" variants to work on any element, Tailwind requires the parent element to have the class "dark". So if the HTML elelemnt, the highest ellemnt, jas teh class "dark" any children with variant "dark:" will get the styling. That would simplify everything immensely, because I coudl get rid of Context altogether, and just have the theme-swicth apply the class "dark" to the HTML element or remove it.
Am I getting this right?
And because I don't have to use conetxt, not eveythig woild be a client component, and I could have server compoenents back!
This si exciting!
Gray-tailed Tattler
Ya that sounds right. Just one conditional class that’s bound to some top level state
American BobtailOP
Great, Thanks a bunch!
@Gray-tailed Tattler Ya that sounds right. Just one conditional class that’s bound to some top level state
American BobtailOP
On second thouhgt, how would I then force React to do a global re-render? There's this trick of applying a key=""" attribute and if that value changes usually React rre-renders. But I don't think it applies to high-level eleemnts like HYML or Body, does it?
Gray-tailed Tattler
Can I ask why you need a full rerender upon theme change?
American BobtailOP
Here's my revised thought process:
Step 1: Adding or removing the "dark" class directly to/from the HTML element would be a simpler and more elegant solution. Currently, I check the isDarkModeOn state to dynamically add the "dark" class to the outer element of every component. Transitioning to directly manipulating the HTML element would improve the implementation.
Step 2: I now need to trigger a re-render in React. The theme switch is omnipresent, residing in the navbar, allowing the user to switch themes at any point. The application must respond by changing colors, including the scrollbar. A global re-render is necessary when the theme changes, as all components are affected by a shift in the color palette.
Getting rid of Context would also be beneficial. If I wrap the layout in a Context provider, I essentially turn the entire app into a client component, forfeiting the advantages of Server Components. A solution that involves only changing the class="dark" in the HTML and forcing a re-render without using Context would be ideal.
Does this make sense?
Step 1: Adding or removing the "dark" class directly to/from the HTML element would be a simpler and more elegant solution. Currently, I check the isDarkModeOn state to dynamically add the "dark" class to the outer element of every component. Transitioning to directly manipulating the HTML element would improve the implementation.
Step 2: I now need to trigger a re-render in React. The theme switch is omnipresent, residing in the navbar, allowing the user to switch themes at any point. The application must respond by changing colors, including the scrollbar. A global re-render is necessary when the theme changes, as all components are affected by a shift in the color palette.
Getting rid of Context would also be beneficial. If I wrap the layout in a Context provider, I essentially turn the entire app into a client component, forfeiting the advantages of Server Components. A solution that involves only changing the class="dark" in the HTML and forcing a re-render without using Context would be ideal.
Does this make sense?
Gray-tailed Tattler
Not really
Your JS should be unaware of styles if you’re using tailwind.
Tailwind JIT compilation will include all the dark and light styles in the bundle.
Unless you’re doing some crazy client side calculations based off css values or something I couldn’t imagine why you’d need the rerender.
There is a distinction tho between dark/light Theme versus color variants of a section or component. But as far as I understand we’re talking about the site “themeâ€
Wait. Did you conditionally use theme variant classes based on state?
American BobtailOP
Yes, it's plain old light/dark theme.
With Tailwind, once I stick a "dark" class onto HTML element, any child element with "dark: ...." will comply. BUT I then have to make React re-render globally. The theme switch is in the navbar
With Tailwind, once I stick a "dark" class onto HTML element, any child element with "dark: ...." will comply. BUT I then have to make React re-render globally. The theme switch is in the navbar
But eveything must change, the scrollbar, the components themselves , etc
Gray-tailed Tattler
But why??
Why the rerender
American BobtailOP
The user enters the app. Light theme is on. User clicks to change theme to dark. Now React must re-render because the global theme has changed
If Recat doesn't re-render, sure, the classes have dynamically changed, but the user sees no change, right?
Gray-tailed Tattler
The only things reactively responding to the theme change in terms of react should be those connected to the theme state variable.
Which should only be your condition class rendering on html el
@American Bobtail If Recat doesn't re-render, sure, the classes have dynamically changed, but the user sees no change, right?
Gray-tailed Tattler
Yes user should immediately see the change
Go try it
American BobtailOP
Yes, and privously I had a context variable which was also a state variable, meaning, once changed it would trigger a re-render. But taht requires wrapping the entire app in a context provider , thus making it all client side. That's what I was trying to avoid
Someone else emntioned using cookies to avoid wrapping the entire app ina conetxt provider, thus preserving the ser side nature of components, but taht's currently too advanced for me
Gray-tailed Tattler
Either you’re overthinking it or I’m under thinking it. Lol. I mean it should literally be this easy https://jamesauble.com/blog/tailwind-dark-mode-in-60-seconds
American BobtailOP
Yes, but that means the user cannot dynamically change theme. Dynamically changing theme requires a re-render
AH , ISEE IT NOW
YOU ARE RIGHT
Gray-tailed Tattler
No it doesn’t
Ya this isn’t about react
American BobtailOP
ALL I HAVE TO DO IS ADD /REMOVE "dark" from the html
Gray-tailed Tattler
Lol ya
American BobtailOP
But let's say current tehme is light and I tehn add dark class, the class of HTML element will have change. But taht doesn't mean React will troactively adapt, will it? That's the issue I'm facing
Gray-tailed Tattler
You can have a site as big as Facebook and change the entire theme without js
American BobtailOP
But will the change be innediately visible?
Gray-tailed Tattler
Could use checkbox element and use the css cascade.
American BobtailOP
In other words, will teh addition /remocal of class "dark" to HTML element be reflected immediately on screen?
Gray-tailed Tattler
Try it
But answer is yes
American BobtailOP
I'm surprised. That's not what I would have expected theoretically
Gray-tailed Tattler
React isn’t that special. This is a relationship between the DOM and your browser
American BobtailOP
So changes to classes trigger re-renders?
Gray-tailed Tattler
Rerender of react? If they’re not being watched no
American BobtailOP
Ok, I'm a bit puzzled, but I trust you, so will try it out
Gray-tailed Tattler
If you mean a repaint of the styles on your page, that has little to do with react
American BobtailOP
Yes, taht's what I mean. I mean a div going from white background to black background as soon as the user clicks on that theme toggle.
Gray-tailed Tattler
Oh ya that’s not a rerender in anyway that we would use the word.
But yes they will change visually on the page
American BobtailOP
What's the correct term?
Gray-tailed Tattler
I think technically that’s a repaint.
American BobtailOP
So re-render has to do with actial content change, whereas re-paint is change in style?
Gray-tailed Tattler
That term render is typically associated with manipulating the actual DOM
American BobtailOP
Ah, so structural changes to the DOM (adding / removing ndoes, etc )
Gray-tailed Tattler
When a color changes on your page. It may be because the dom changed but it doesn’t have to be
Think of an animation.
One class is added but the background could cycle thru all the colors of the rainbow
But render has many meanings and interpretations
American BobtailOP
So changing classes can lead to re-paints? I didn't know taht. Thanks. This has been most helpful. I'm going to try out the solution and will keep you posted.
Thanks a million!
Thanks a million!
Gray-tailed Tattler
I’m not an authority on all of them. Or any of them. Needless to say your simple dark class on the html el should work granted you used all the right variant modifier utilities
In tailwind.
Sounds good. Good luck!
@Gray-tailed Tattler I’m not an authority on all of them. Or any of them. Needless to say your simple dark class on the html el should work granted you used all the right variant modifier utilities
American BobtailOP
Quick update.
I ran a quick next,js app just to test the feature...and...it
WORKED!
I'm speachless.
This theme swicther has taught me so much. Your help has been priceless. Thank you so much. I will never mistake re-paint for re-redner ever again!
Thank you! Kudos!
I ran a quick next,js app just to test the feature...and...it
WORKED!
I'm speachless.
This theme swicther has taught me so much. Your help has been priceless. Thank you so much. I will never mistake re-paint for re-redner ever again!
Thank you! Kudos!
Gray-tailed Tattler
Hah awesome ðŸ‘