Repository: tailwindlabs/headlessui
Pull request #3058 (2024-03-26 17:30:49)

Expose the `--button-width` CSS variable on the `PopoverPanel` component
This PR exposes the `--button-width` CSS variable on the `PopoverPanel` component, similar to all are other components that accept an `anchor` prop.


vercel[bot]: [vc]: #UdWnDM6MSc17QVDVVb5/p1M1vbIcaseX78+nxcn3BVA=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJoZWFkbGVzc3VpLXJlYWN0Iiwicm9vdERpcmVjdG9yeSI6InBsYXlncm91bmRzL3JlYWN0IiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3RhaWx3aW5kbGFicy9oZWFkbGVzc3VpLXJlYWN0L0pDa3RyUkNtQjQ1ejNiejhrRzFHTGJiaGhDNEYiLCJwcmV2aWV3VXJsIjoiaGVhZGxlc3N1aS1yZWFjdC1naXQtZmVhdC1hZGQtcG9wb3Zlci1idXR0b24td2lkdGgtdGFpbHdpbmRsYWJzLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiUEVORElORyIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJoZWFkbGVzc3VpLXJlYWN0LWdpdC1mZWF0LWFkZC1wb3BvdmVyLWJ1dHRvbi13aWR0aC10YWlsd2luZGxhYnMudmVyY2VsLmFwcCJ9fV19
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **headlessui-react** | 🔄 Building ([Inspect](https://vercel.com/tailwindlabs/headlessui-react/JCktrRCmB45z3bz8kG1GLbbhhC4F)) | [Visit Preview](https://vercel.live/open-feedback/headlessui-react-git-feat-add-popover-button-width-tailwindlabs.vercel.app?via=pr-comment-visit-preview-link&passThrough=1) | 💬 [**Add feedback**](https://vercel.live/open-feedback/headlessui-react-git-feat-add-popover-button-width-tailwindlabs.vercel.app?via=pr-comment-feedback-link) | Mar 26, 2024 5:30pm |



Patch:
diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md
index 7f70211..e010ef6 100644
--- a/packages/@headlessui-react/CHANGELOG.md
+++ b/packages/@headlessui-react/CHANGELOG.md
@@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - Accept optional `strategy` for the `anchor` prop ([#3034](https://github.com/tailwindlabs/headlessui/pull/3034))
 - Expose `--input-width` and `--button-width` CSS variables on the `ComboboxOptions` component ([#3057](https://github.com/tailwindlabs/headlessui/pull/3057))
+- Expose the `--button-width` CSS variable on the `PopoverPanel` component ([#3058](https://github.com/tailwindlabs/headlessui/pull/3058))
 
 ## [2.0.0-alpha.4] - 2024-01-03
 
diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx
index e90bb96..6a26b21 100644
--- a/packages/@headlessui-react/src/components/popover/popover.tsx
+++ b/packages/@headlessui-react/src/components/popover/popover.tsx
@@ -23,6 +23,7 @@ import React, {
   type Ref,
 } from 'react'
 import { useActivePress } from '../../hooks/use-active-press'
+import { useElementSize } from '../../hooks/use-element-size'
 import { useEvent } from '../../hooks/use-event'
 import { useEventListener } from '../../hooks/use-event-listener'
 import { useId } from '../../hooks/use-id'
@@ -913,7 +914,10 @@ function PanelFn<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
           }
         : undefined,
     tabIndex: -1,
-    ...(style ? { style } : {}),
+    style: {
+      ...style,
+      '--button-width': useElementSize(state.button, true).width,
+    } as React.CSSProperties,
   })
 
   let direction = useTabDirection()
diff --git a/packages/@headlessui-react/src/hooks/use-element-size.ts b/packages/@headlessui-react/src/hooks/use-element-size.ts
index 09e3d96..c05fea9 100644
--- a/packages/@headlessui-react/src/hooks/use-element-size.ts
+++ b/packages/@headlessui-react/src/hooks/use-element-size.ts
@@ -7,11 +7,14 @@ function computeSize(element: HTMLElement | null) {
   return { width, height }
 }
 
-export function useElementSize(ref: React.MutableRefObject<HTMLElement | null>, unit = false) {
-  let [size, setSize] = useState(() => computeSize(ref.current))
+export function useElementSize(
+  ref: React.MutableRefObject<HTMLElement | null> | HTMLElement | null,
+  unit = false
+) {
+  let element = ref === null ? null : 'current' in ref ? ref.current : ref
+  let [size, setSize] = useState(() => computeSize(element))
 
   useIsoMorphicEffect(() => {
-    let element = ref.current
     if (!element) return
 
     let observer = new ResizeObserver(() => {
@@ -23,7 +26,7 @@ export function useElementSize(ref: React.MutableRefObject<HTMLElement | null>,
     return () => {
       observer.disconnect()
     }
-  }, [ref])
+  }, [element])
 
   if (unit) {
     return {


Test patch:
diff --git a/packages/@headlessui-react/src/components/popover/popover.test.tsx b/packages/@headlessui-react/src/components/popover/popover.test.tsx
index 9230234..cdcc775 100644
--- a/packages/@headlessui-react/src/components/popover/popover.test.tsx
+++ b/packages/@headlessui-react/src/components/popover/popover.test.tsx
@@ -22,6 +22,12 @@ let act = _act as unknown as <T>(fn: () => T) => PromiseLike<T>
 
 jest.mock('../../hooks/use-id')
 
+// @ts-expect-error
+global.ResizeObserver = class FakeResizeObserver {
+  observe() {}
+  disconnect() {}
+}
+
 afterAll(() => jest.restoreAllMocks())
 
 function nextFrame() {