Skip to content

feat(Tabs): add before-change event #3493

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking β€œSign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/components/content/examples/TabsExampleBeforeChange.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script setup lang="ts">
const items = [{
label: 'Tab1',
icon: 'i-heroicons-information-circle',
content: 'This is the content shown for Tab1'
}, {
label: 'Tab2',
icon: 'i-heroicons-arrow-down-tray',
content: 'And, this is the content for Tab2'
}, {
label: 'Tab3',
icon: 'i-heroicons-eye-dropper',
content: 'Finally, this is the content for Tab3'
}]
function onBeforeChange(prevIndex, next) {
if (window.confirm('Do you want to change tab?')) {
const prevItem = items[prevIndex]
alert(`Tab was changed! Previous tab is ${prevItem.label}`)
return next()
}
alert('Tab was not changed!')
}
</script>

<template>
<UTabs :items="items" @before-change="onBeforeChange" />
</template>
14 changes: 14 additions & 0 deletions docs/content/2.components/tabs.md
Original file line number Diff line number Diff line change
@@ -66,6 +66,20 @@ componentProps:

You can use the `content` prop and set it to `false` to avoid the rendering of the HTML content if you don't need it.

#### Listen to @before-change event

You can execute code before the `@change` event is triggered by using the `@before-change` event. This event emits the index of the previously selected item and provides a second `next()` argument, which you can use to continue handling the `@change` event.

::component-example
---
component: 'tabs-example-before-change'
componentProps:
class: 'w-full'
---
::

This event is useful when you need to validate data before switching tabs or display a confirmation window with a relevant message to users.

### Control the selected index

Use a `v-model` to control the selected index.
13 changes: 10 additions & 3 deletions src/runtime/components/navigation/Tabs.vue
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@
</template>

<script lang="ts">
import { toRef, ref, watch, onMounted, defineComponent, nextTick } from 'vue'
import { toRef, ref, watch, onMounted, defineComponent, nextTick, getCurrentInstance } from 'vue'
import type { PropType } from 'vue'
import { TabGroup as HTabGroup, TabList as HTabList, Tab as HTab, TabPanels as HTabPanels, TabPanel as HTabPanel, provideUseId } from '@headlessui/vue'
import { useResizeObserver } from '@vueuse/core'
@@ -113,7 +113,7 @@ export default defineComponent({
default: () => ({})
}
},
emits: ['update:modelValue', 'change'],
emits: ['update:modelValue', 'change', 'beforeChange'],
setup(props, { emit }) {
const { ui, attrs } = useUI('tabs', toRef(props, 'ui'), config, toRef(props, 'class'))
@@ -122,6 +122,7 @@ export default defineComponent({
const markerRef = ref<HTMLElement>()
const selectedIndex = ref<number | undefined>(props.modelValue || props.defaultIndex)
const beforeChangeEventPassed = ref(!!getCurrentInstance()?.vnode.props?.onBeforeChange)
// Methods
@@ -142,7 +143,13 @@ export default defineComponent({
markerRef.value.style.height = `${tab.offsetHeight}px`
}
function onChange(index: number) {
async function onChange(index: number) {
if (beforeChangeEventPassed.value) {
await new Promise((resolve) => {
emit('beforeChange', selectedIndex.value, resolve)
})
}
selectedIndex.value = index
emit('change', index)

Unchanged files with check annotations Beta

indicator?: { percent: number, value: number }
label?: { percent: number, value: number }
}>,
props: {

Check warning on line 53 in src/runtime/components/elements/Meter.vue

GitHub Actions / ci (ubuntu-latest, 20)

The "props" property should be above the "slots" property on line 49
value: {
type: Number,
default: 0