GitHub

File tree

  • docs

    • app

      • components/content/examples/toaster

    • content/docs/2.components

  • playgrounds/nuxt/app

    • pages/components

  • src/runtime

    • components

    • composables

Original file line numberDiff line numberDiff line change

@@ -1,8 +1,9 @@

11

export default defineAppConfig({

22

toaster: {

33

position: 'bottom-right' as const,

4-

expand: true,

5-

duration: 5000

4+

duration: 5000,

5+

max: 5,

6+

expand: true

67

},

78

theme: {

89

radius: 0.25,

Original file line numberDiff line numberDiff line change

@@ -0,0 +1,25 @@

1+

<script setup lang="ts">

2+

const appConfig = useAppConfig()

3+

</script>

4+
5+

<template>

6+

<div>

7+

<UFormField

8+

label="toaster.max"

9+

size="sm"

10+

:ui="{

11+

wrapper: 'bg-elevated/50 rounded-l-sm flex border-r border-accented',

12+

label: 'text-muted px-2 py-1.5',

13+

container: 'mt-0'

14+

}"

15+

class="inline-flex ring ring-accented rounded-sm"

16+

>

17+

<UInput

18+

v-model="appConfig.toaster.max"

19+

color="neutral"

20+

variant="soft"

21+

:ui="{ base: 'rounded-sm rounded-l-none min-w-12' }"

22+

/>

23+

</UFormField>

24+

</div>

25+

</template>

Original file line numberDiff line numberDiff line change

@@ -256,18 +256,44 @@ name: 'toast-example'

256256

:toaster-duration-example

257257

::

258258
259-

::note{to="https://github.com/nuxt/ui/blob/v4/docs/app/app.config.ts#L5"}

259+

::note{to="https://github.com/nuxt/ui/blob/v4/docs/app/app.config.ts#L4"}

260260

In this example, we use the `AppConfig` to configure the `duration` prop of the `Toaster` component globally.

261261

::

262262
263-

### Stacked toasts

263+

### Change global max :badge{label="Soon"}

264264
265-

Set the `toaster.expand` prop to `false` on the [App](/docs/components/app#props) component to display stacked toasts.

265+

Change the `toaster.max` prop on the [App](/docs/components/app#props) component to change the max number of toasts displayed at once.

266266
267-

::tip

268-

You can hover over the toasts to expand them. This will also pause the timer of the toasts.

267+

```vue [app.vue]

268+

<script setup lang="ts">

269+

const toaster = { max: 3 }

270+

</script>

271+
272+

<template>

273+

<UApp :toaster="toaster">

274+

<NuxtPage />

275+

</UApp>

276+

</template>

277+

```

278+
279+

::component-example

280+

---

281+

prettier: true

282+

name: 'toast-example'

283+

---

284+
285+

#options

286+

:toaster-max-example

287+

::

288+
289+

::note{to="https://github.com/nuxt/ui/blob/v4/docs/app/app.config.ts#L5"}

290+

In this example, we use the `AppConfig` to configure the `max` prop of the `Toaster` component globally.

269291

::

270292
293+

### Stacked toasts

294+
295+

Set the `toaster.expand` prop to `false` on the [App](/docs/components/app#props) component to display stacked toasts (inspired by [Sonner](https://sonner.emilkowal.ski/)).

296+
271297

```vue [app.vue]

272298

<script setup lang="ts">

273299

const toaster = { expand: true }

@@ -280,6 +306,10 @@ const toaster = { expand: true }

280306

</template>

281307

```

282308
309+

::tip

310+

You can hover over the toasts to expand them. This will also pause the timer of the toasts.

311+

::

312+
283313

::component-example

284314

---

285315

prettier: true

@@ -290,7 +320,7 @@ name: 'toast-example'

290320

:toaster-expand-example

291321

::

292322
293-

::note{to="https://github.com/nuxt/ui/blob/v4/docs/app/app.config.ts#L4"}

323+

::note{to="https://github.com/nuxt/ui/blob/v4/docs/app/app.config.ts#L6"}

294324

In this example, we use the `AppConfig` to configure the `expand` prop of the `Toaster` component globally.

295325

::

296326
Original file line numberDiff line numberDiff line change

@@ -2,8 +2,9 @@ export default defineAppConfig({

22

dir: 'ltr',

33

toaster: {

44

position: 'bottom-right' as const,

5-

expand: true,

6-

duration: 5000

5+

duration: 5000,

6+

max: 5,

7+

expand: true

78

},

89

ui: {

910

colors: {

Original file line numberDiff line numberDiff line change

@@ -129,6 +129,7 @@ function removeToast() {

129129

<UCheckbox v-model="appConfig.toaster.expand" label="Expand" />

130130

<USelect v-model="appConfig.toaster.position" :items="positions" placeholder="Position" />

131131

<UInput v-model="appConfig.toaster.duration" label="Duration" type="number" />

132+

<UInput v-model="appConfig.toaster.max" label="Max" type="number" />

132133

</Navbar>

133134
134135

<div class="flex items-center gap-2">

Original file line numberDiff line numberDiff line change

@@ -27,6 +27,11 @@ export interface ToasterProps extends Omit<ToastProviderProps, 'swipeDirection'>

2727

* @defaultValue true

2828

*/

2929

portal?: boolean | string | HTMLElement

30+

/**

31+

* Maximum number of toasts to display at once.

32+

* @defaultValue 5

33+

*/

34+

max?: number

3035

class?: any

3136

ui?: Toaster['slots']

3237

}

@@ -41,11 +46,11 @@ export default {

4146

</script>

4247
4348

<script setup lang="ts">

44-

import { ref, computed, toRef } from 'vue'

49+

import { ref, computed, toRef, provide } from 'vue'

4550

import { ToastProvider, ToastViewport, ToastPortal, useForwardProps } from 'reka-ui'

4651

import { reactivePick } from '@vueuse/core'

4752

import { useAppConfig } from '#imports'

48-

import { useToast } from '../composables/useToast'

53+

import { useToast, toastMaxInjectionKey } from '../composables/useToast'

4954

import { usePortal } from '../composables/usePortal'

5055

import { omit } from '../utils'

5156

import { tv } from '../utils/tv'

@@ -55,13 +60,16 @@ const props = withDefaults(defineProps<ToasterProps>(), {

5560

expand: true,

5661

portal: true,

5762

duration: 5000,

58-

progress: true

63+

progress: true,

64+

max: 5

5965

})

6066

defineSlots<ToasterSlots>()

6167
6268

const { toasts, remove } = useToast()

6369

const appConfig = useAppConfig() as Toaster['AppConfig']

6470
71+

provide(toastMaxInjectionKey, toRef(() => props.max))

72+
6573

const providerProps = useForwardProps(reactivePick(props, 'duration', 'label', 'swipeThreshold'))

6674

const portalProps = usePortal(toRef(() => props.portal))

6775
Original file line numberDiff line numberDiff line change

@@ -1,16 +1,20 @@

1-

import { ref, nextTick } from 'vue'

1+

import type { Ref, InjectionKey } from 'vue'

2+

import { ref, nextTick, inject } from 'vue'

23

import { useState } from '#imports'

34

import type { ToastProps, ToastEmits } from '../types'

45

import type { EmitsToProps } from '../types/utils'

56
7+

export const toastMaxInjectionKey: InjectionKey<Ref<number | undefined>> = Symbol('nuxt-ui.toast-max')

8+
69

export interface Toast extends Omit<ToastProps, 'defaultOpen'>, EmitsToProps<ToastEmits> {

710

id: string | number

811

onClick?: (toast: Toast) => void

912

}

1013
1114

export function useToast() {

1215

const toasts = useState<Toast[]>('toasts', () => [])

13-

const maxToasts = 5

16+

const max = inject(toastMaxInjectionKey, undefined)

17+
1418

const running = ref(false)

1519

const queue: Toast[] = []

1620

@@ -28,7 +32,7 @@ export function useToast() {

2832
2933

await nextTick()

3034
31-

toasts.value = [...toasts.value, toast].slice(-maxToasts)

35+

toasts.value = [...toasts.value, toast].slice(-(max?.value ?? 5))

3236

}

3337
3438

running.value = false

Read the original on github.com ↗