Headless UI Transition.child errors to "Did you forget to passthrough the `ref` to the actual DOM node" - tailwind-css

I'm building a sidebar with the Transition and Dialog Headless UI components.
Transition docs
When I break out the code that's passed between <Transition.Child> to it's own component. I get this error:
Unhandled Runtime Error
Error: Did you forget to passthrough the `ref` to the actual DOM node?
Call Stack
eval
node_modules/#headlessui/react/dist/components/transitions/transition.js (1:3632)
Failing code:
<Transition.Child as={Fragment}>
<Cart
cancelButtonReference={cancelButtonReference}
setCartOpen={setCartOpen}
checkoutUrl={checkoutUrl}
removeCartItem={removeCartItem}
clearCart={clearCart}
cartLoading={cartLoading}
incrementCartItem={incrementCartItem}
decrementCartItem={decrementCartItem}
cartTotal={cartTotal}
cart={cart}
/>
</Transition.Child>
Working code:
<Transition.Child as={Fragment}>
<div>
...
</div>
</Transition.Child>
I understand the error I believe, which is that when I break out the code to it's own component Transition.Child wants me to pass a ref so that React knows that it should render a component and not a fragment.
If I remove as={Fragment}, which makes the Transition default to a div the error goes away, but then I get an unneeded div..
What ref do I need to pass? This is what I don't get.

You don't need to pass a ref, but the component needs to accept one and set it on the actual element.
The div element will accept the ref, which is why that method works.
Try creating the Cart component using React.forwardRef and set the ref on the div.
const Cart = React.forwardRef((props, forwardedRef) => {
return (
<div ref={forwardedRef}>
...
</div>
)
})

I ran into the same issue, and just found a solution—which you basically already said, too.
Through some testing, as you pointed out, it works when surrounding the component with the <div>…</div> tags.
Although I don't really understand it, it's clear that Headless UI's <Transition> tag wants to pass a reference to it's immediate child. With normal HTML tags, like <div>, it does it automatically. When using a component, it can't do it in the same way.
Solution #1
(Broken*)
I'm sure there's a more "proper" solution to this, but I found that—as we don't want <Transition> to render any HTML tags—you can just surround your component with another React fragment:
<Transition.Child as={Fragment}>
<> {/* <— Our new Fragment */}
<Cart
cancelButtonReference={cancelButtonReference}
setCartOpen={setCartOpen}
checkoutUrl={checkoutUrl}
removeCartItem={removeCartItem}
clearCart={clearCart}
cartLoading={cartLoading}
incrementCartItem={incrementCartItem}
decrementCartItem={decrementCartItem}
cartTotal={cartTotal}
cart={cart}
/>
</>
</Transition.Child>
This was working for me for a bit, but then just stopped working.*
Solution #2
(This also appears to not function correctly*)
As a secondary option, if you don't mind having another element rendered on the DOM, you can set the <Transition> to render as={'div'} (this is the default, so you don't actually have to define the prop), and then set the CSS display to contents:
<Transition.Child style={{display: 'contents'}}> {/* <— display set to contents */}
<Cart
cancelButtonReference={cancelButtonReference}
setCartOpen={setCartOpen}
checkoutUrl={checkoutUrl}
removeCartItem={removeCartItem}
clearCart={clearCart}
cartLoading={cartLoading}
incrementCartItem={incrementCartItem}
decrementCartItem={decrementCartItem}
cartTotal={cartTotal}
cart={cart}
/>
</Transition.Child>
If you're not familiar with display: contents, Manuel Rego give this description:
display: contents makes that the div doesn’t generate any box, so its background, border and padding are not rendered. However the inherited properties like color and font have effect on the child (span element) as expected.
Source
It seems that this technically fixes the ref issue, but because of the way display: contents works, all other applied CSS doesn't render.*
As I just discovered, neither of these works, I am looking into other solutions.

Related

Move a child element from shadow dom to light dom on document.ready

I defined a custom-element using web componenet:
<universal-form>
<slot name="inner-input">
</universal-form>
This custom-element itself is placed inside another shadow dom:
<my-dashboard>
#shadow-root
<div id="shadow-container">
<universal-form>
...
<input type="datepicker" id="to-be-exposed" slot="inner-input"/>
</universal-form>
</div>
...
</my-dashboard>
** note: for some of you might suggest putting the <universal-form> inside a slot of the <my-dashboard>, instead of placing it directly into the <my-dashboard> shadow-root, this route is ruled out because of some other implementation requirements.
Now I'd like to be able to style the input#to-be-exposed from the webpage's css file, so it needs to be accessible from the light dom when the document is rendered ready.
What is some best practice to achieve this?
An option would be to drop the shadowDom form the dashboard element in this case as an element that has a shadow attached doesn't have a light dom visible anymore.
The element won't mind that, things that are leaking in are exactly what you want, namely style from the parent window.
Implementation is simple, instead appending elements to the attached shadow append them directly in to the element.
Example of a shadowless element :
class MyElement extends HTMLElement {
constructor(){
super();
this.innerHTML = `elements here`;
}
}

CSS isolation in Blazor

I don't know how exactly this new feature must be work in Blazor, but I think that the current implementation work wrong. Below some typical situation:
Layout for some blazor component:
<button>
<span>Some Text</span>
<Icon> ... </Icon>
</button>
source scss file ...
that will be translated in to something like ...
after apply of CSS isolation we have :-( ...
Why NOT THIS????
And of course in DOM after rendering we have only button with scope id "b-l4md7xqlo6", but not span itself! Span don't have this attribute, and in my situation I don't need it.
In other words, after applying of scope id, the result CSS not equal exactly to my declared CSS!
Any ideas?
Thanks,
Nikolai

How can I style a sub element of a Fluent UI component in React?

I am trying to style an HTML element inside the component from the Fluent UI React library.
What I want to do is put the "On" / "Off" text to the left of the toggle rather than on the left. When I look at my "compiled" code I can see that the component is translated into:
<div>
<label></label>
<div id="target-me">
<button>
<span></span>
</button>
<label></label>
</div>
</div>
I want to add an inline-flex to the target-me div and set flex-flow property to row-reverse in order to get the button element to the right of the label element. The problem is, I can't manage to target the "target-me" div in my code.
How can I achieve this without rewriting a custom component ?
Thanks!
Ok, well I found the answer to my own question so here it is:
<Toggle styles={{ container: { flexFlow: "row-reverse" } }} />
Essentially you can target different parts of the component (root, container, label..) by using the styles property. Use VS Code's Intellisense to find out what elements you can target inside the component and then just give it some regular CSS-in-JS that you want.

Can't find a way to tweak css of the "React Lazy Load Image Component"

I am referring to the React Lazy Load Image Component.
I need to tweak the display attribute of the image I am rendering with this library. But can't seem to find any way.
I tried to wrap the component with a div and use style={{display: 'inline'}}, but it didn't work.
<div className="ui image" style={{ display: 'inline' }}>
<LazyLoadImage
src={src}
effect="blur"
/>
</div>
I am using this portion of code inside a <Card/> component. The default css of the library contains display: inline-block which is making my image have an extra border at the bottom. I don't want it.
P.S.
I am using Semantic UI for my entire project. I want to use whatever style Semantic is providing me. That's why I need to teak the display attribute of this library.

Use variables to update internal CSS inside an angular component?

I would like to modify quite a large amount of styles on a page through a customisable panel. When a user clicks an option, the content on the page will completely change based on whatever was clicked.
This cannot be a scenario where a class is appended to a parent element and use CSS/LESS to adjust accordingly. For this scenario (for requirement reasons) the CSS needs to be internal on the angular component HTML.
Is it possible to have a value in the component TS like this:
myNewColour: "red"
That can then be used in an internal style sheet that's inside my angular component.html like this?:
<style>
.myContainer { background: myNewColour }
</style>
<!-- HTML Content -->
<div class="myContainer"> Stuff </div>
Any help with this would be appreciated! :)
"Internal in the HTML template" is called inline style ;) Apart from that, you can use ngStyle like so
<tag [ngStyle]="{'background': myNewColour}"></tag>
EDIT if it makes your code too long, what you can do is simply
let customStyle = {
'background': this.myNewColour
};
And in your tag, simply
<tag [ngStyle]="customStyle"></tag>

Resources