Repository: tailwindlabs/headlessui
Pull request #2918 (2024-01-09 14:40:15)

Expose `disabled` state on `<Tab />` component
This PR fixes an issue where `disabled` on the `<Tab/>` component wasn't exposed.

This will expose it such that you can use it with `ui-disabled`. In the Alpha version of React, you can also use `data-[disabled]` because it will be exposed as `data-disabled` over there as well.

Marked it as fixed because we already accept the `disabled` state and expose it in some other components so considered it "missing".

Fixes: #2864


vercel[bot]: [vc]: #m5JwGxZRy1nv50m24FNcA4QtovnHyuXS1s/0r9qhD/s=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJoZWFkbGVzc3VpLXJlYWN0Iiwicm9vdERpcmVjdG9yeSI6InBsYXlncm91bmRzL3JlYWN0IiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3RhaWx3aW5kbGFicy9oZWFkbGVzc3VpLXJlYWN0LzNQZ2o1R0tzWVphUlY3d1pydm9iZUZwRTdXVloiLCJwcmV2aWV3VXJsIjoiaGVhZGxlc3N1aS1yZWFjdC1naXQtZml4LWlzc3VlLTI4NjQtdGFpbHdpbmRsYWJzLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiUEVORElORyIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJoZWFkbGVzc3VpLXJlYWN0LWdpdC1maXgtaXNzdWUtMjg2NC10YWlsd2luZGxhYnMudmVyY2VsLmFwcCJ9fSx7Im5hbWUiOiJoZWFkbGVzc3VpLXZ1ZSIsInJvb3REaXJlY3RvcnkiOiJwbGF5Z3JvdW5kcy92dWUiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vdGFpbHdpbmRsYWJzL2hlYWRsZXNzdWktdnVlLzRBUHBuRVhnVTZtV2tvZW1QYWRyU0NZcENtMlAiLCJwcmV2aWV3VXJsIjoiaGVhZGxlc3N1aS12dWUtZ2l0LWZpeC1pc3N1ZS0yODY0LXRhaWx3aW5kbGFicy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IlBFTkRJTkciLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoiaGVhZGxlc3N1aS12dWUtZ2l0LWZpeC1pc3N1ZS0yODY0LXRhaWx3aW5kbGFicy52ZXJjZWwuYXBwIn19XX0=
**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/3Pgj5GKsYZaRV7wZrvobeFpE7WVZ)) | [Visit Preview](https://vercel.live/open-feedback/headlessui-react-git-fix-issue-2864-tailwindlabs.vercel.app?via=pr-comment-visit-preview-link&passThrough=1) | 💬 [**Add feedback**](https://vercel.live/open-feedback/headlessui-react-git-fix-issue-2864-tailwindlabs.vercel.app?via=pr-comment-feedback-link) | Jan 9, 2024 2:40pm |
| **headlessui-vue** | 🔄 Building ([Inspect](https://vercel.com/tailwindlabs/headlessui-vue/4APpnEXgU6mWkoemPadrSCYpCm2P)) | [Visit Preview](https://vercel.live/open-feedback/headlessui-vue-git-fix-issue-2864-tailwindlabs.vercel.app?via=pr-comment-visit-preview-link&passThrough=1) | 💬 [**Add feedback**](https://vercel.live/open-feedback/headlessui-vue-git-fix-issue-2864-tailwindlabs.vercel.app?via=pr-comment-feedback-link) | Jan 9, 2024 2:40pm |




Patch:
diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md
index faa061e..1b7359e 100644
--- a/packages/@headlessui-react/CHANGELOG.md
+++ b/packages/@headlessui-react/CHANGELOG.md
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
-- Nothing yet!
+### Fixed
+
+- Expose `disabled` state on `<Tab />` component ([#2918](https://github.com/tailwindlabs/headlessui/pull/2918))
 
 ## [2.0.0-alpha.4] - 2024-01-03
 
diff --git a/packages/@headlessui-react/src/components/tabs/tabs.tsx b/packages/@headlessui-react/src/components/tabs/tabs.tsx
index 24ea498..e4de17f 100644
--- a/packages/@headlessui-react/src/components/tabs/tabs.tsx
+++ b/packages/@headlessui-react/src/components/tabs/tabs.tsx
@@ -388,6 +388,7 @@ type TabRenderPropArg = {
   active: boolean
   autofocus: boolean
   selected: boolean
+  disabled: boolean
 }
 type TabPropsWeControl = 'aria-controls' | 'aria-selected' | 'role' | 'tabIndex'
 
@@ -512,8 +513,9 @@ function TabFn<TTag extends ElementType = typeof DEFAULT_TAB_TAG>(
         active,
         focus,
         autofocus: props.autoFocus ?? false,
+        disabled: props.disabled ?? false,
       }) satisfies TabRenderPropArg,
-    [selected, hover, focus, active, props.autoFocus]
+    [selected, hover, focus, active, props.autoFocus, props.disabled]
   )
 
   let ourProps = mergeProps(
diff --git a/packages/@headlessui-vue/CHANGELOG.md b/packages/@headlessui-vue/CHANGELOG.md
index a372c35..5ac8cff 100644
--- a/packages/@headlessui-vue/CHANGELOG.md
+++ b/packages/@headlessui-vue/CHANGELOG.md
@@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Add `immediate` prop to `<Combobox />` for immediately opening the Combobox when the `input` receives focus ([#2686](https://github.com/tailwindlabs/headlessui/pull/2686))
 - Add `virtual` prop to `Combobox` component ([#2779](https://github.com/tailwindlabs/headlessui/pull/2779))
 
+### Fixed
+
+- Expose `disabled` state on `<Tab />` component ([#2918](https://github.com/tailwindlabs/headlessui/pull/2918))
+
 ## [1.7.17] - 2024-01-08
 
 ### Fixed
diff --git a/packages/@headlessui-vue/src/components/tabs/tabs.ts b/packages/@headlessui-vue/src/components/tabs/tabs.ts
index 4e5156e..591c92c 100644
--- a/packages/@headlessui-vue/src/components/tabs/tabs.ts
+++ b/packages/@headlessui-vue/src/components/tabs/tabs.ts
@@ -423,7 +423,7 @@ export let Tab = defineComponent({
     )
 
     return () => {
-      let slot = { selected: selected.value }
+      let slot = { selected: selected.value, disabled: props.disabled ?? false }
       let { id, ...theirProps } = props
       let ourProps = {
         ref: internalTabRef,


Test patch:
diff --git a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx
index 679a4cb..9cb78f2 100644
--- a/packages/@headlessui-react/src/components/tabs/tabs.test.tsx
+++ b/packages/@headlessui-react/src/components/tabs/tabs.test.tsx
@@ -544,6 +544,7 @@ describe('Rendering', () => {
             active: false,
             focus: false,
             autofocus: false,
+            disabled: false,
           })
         )
         expect(document.querySelector('[data-tab="1"]')).toHaveTextContent(
@@ -553,6 +554,7 @@ describe('Rendering', () => {
             active: false,
             focus: false,
             autofocus: false,
+            disabled: false,
           })
         )
         expect(document.querySelector('[data-tab="2"]')).toHaveTextContent(
@@ -562,6 +564,7 @@ describe('Rendering', () => {
             active: false,
             focus: false,
             autofocus: false,
+            disabled: false,
           })
         )
 
@@ -574,6 +577,7 @@ describe('Rendering', () => {
             active: false,
             focus: false,
             autofocus: false,
+            disabled: false,
           })
         )
         expect(document.querySelector('[data-tab="1"]')).toHaveTextContent(
@@ -583,6 +587,7 @@ describe('Rendering', () => {
             active: false,
             focus: false,
             autofocus: false,
+            disabled: false,
           })
         )
         expect(document.querySelector('[data-tab="2"]')).toHaveTextContent(
@@ -592,6 +597,7 @@ describe('Rendering', () => {
             active: false,
             focus: false,
             autofocus: false,
+            disabled: false,
           })
         )
       })
diff --git a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts
index 96a152e..28a5896 100644
--- a/packages/@headlessui-vue/src/components/tabs/tabs.test.ts
+++ b/packages/@headlessui-vue/src/components/tabs/tabs.test.ts
@@ -463,25 +463,25 @@ describe('Rendering', () => {
       await new Promise<void>(nextTick)
 
       expect(document.querySelector('[data-tab="0"]')).toHaveTextContent(
-        JSON.stringify({ selected: true })
+        JSON.stringify({ selected: true, disabled: false })
       )
       expect(document.querySelector('[data-tab="1"]')).toHaveTextContent(
-        JSON.stringify({ selected: false })
+        JSON.stringify({ selected: false, disabled: false })
       )
       expect(document.querySelector('[data-tab="2"]')).toHaveTextContent(
-        JSON.stringify({ selected: false })
+        JSON.stringify({ selected: false, disabled: false })
       )
 
       await click(getTabs()[1])
 
       expect(document.querySelector('[data-tab="0"]')).toHaveTextContent(
-        JSON.stringify({ selected: false })
+        JSON.stringify({ selected: false, disabled: false })
       )
       expect(document.querySelector('[data-tab="1"]')).toHaveTextContent(
-        JSON.stringify({ selected: true })
+        JSON.stringify({ selected: true, disabled: false })
       )
       expect(document.querySelector('[data-tab="2"]')).toHaveTextContent(
-        JSON.stringify({ selected: false })
+        JSON.stringify({ selected: false, disabled: false })
       )
     })