Timeline
一个组件,显示一系列事件,包括日期、标题、图标或头像。
用法
使用时间轴组件可以显示时间轴中的项目列表。
Mar 15, 2025
Project Kickoff
Kicked off the project with team alignment. Set up project milestones and allocated resources.
Mar 22 2025
Design Phase
User research and design workshops. Created wireframes and prototypes for user testing.
Mar 29 2025
Development Sprint
Frontend and backend development. Implemented core features and integrated with APIs.
Apr 5 2025
Testing & Deployment
QA testing and performance optimization. Deployed the application to production.
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline :items="items" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline :items="items" />
</template>项目
使用items prop作为具有以下属性的对象数组:
date?: stringtitle?: stringdescription?: AvatarPropsicon?: stringavatar?: AvatarPropsvalue?: string | number060x年060x月060x日星期一class?: anyui?: { item?: ClassNameValue, container?: ClassNameValue, indicator?: ClassNameValue, separator?: ClassNameValue, wrapper?: ClassNameValue, date?: ClassNameValue, title?: ClassNameValue, description?: ClassNameValue }
Mar 15, 2025
Project Kickoff
Kicked off the project with team alignment. Set up project milestones and allocated resources.
Mar 22 2025
Design Phase
User research and design workshops. Created wireframes and prototypes for user testing.
Mar 29 2025
Development Sprint
Frontend and backend development. Implemented core features and integrated with APIs.
Apr 5 2025
Testing & Deployment
QA testing and performance optimization. Deployed the application to production.
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline :default-value="2" :items="items" class="w-96" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline :default-value="2" :items="items" class="w-96" />
</template>Color
使用color属性更改时间轴中活动项目的颜色。
Mar 15, 2025
Project Kickoff
Kicked off the project with team alignment. Set up project milestones and allocated resources.
Mar 22 2025
Design Phase
User research and design workshops. Created wireframes and prototypes for user testing.
Mar 29 2025
Development Sprint
Frontend and backend development. Implemented core features and integrated with APIs.
Apr 5 2025
Testing & Deployment
QA testing and performance optimization. Deployed the application to production.
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline color="neutral" :default-value="2" :items="items" class="w-96" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline color="neutral" :default-value="2" :items="items" class="w-96" />
</template>Size
使用size道具更改时间轴的大小。
Mar 15, 2025
Project Kickoff
Kicked off the project with team alignment. Set up project milestones and allocated resources.
Mar 22 2025
Design Phase
User research and design workshops. Created wireframes and prototypes for user testing.
Mar 29 2025
Development Sprint
Frontend and backend development. Implemented core features and integrated with APIs.
Apr 5 2025
Testing & Deployment
QA testing and performance optimization. Deployed the application to production.
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline size="xs" :default-value="2" :items="items" class="w-96" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline size="xs" :default-value="2" :items="items" class="w-96" />
</template>方向
使用orientation道具将时间轴. vertical的方向更改为。
Mar 15, 2025
Project Kickoff
Kicked off the project with team alignment.
Mar 22 2025
Design Phase
User research and design workshops.
Mar 29 2025
Development Sprint
Frontend and backend development.
Apr 5 2025
Testing & Deployment
QA testing and performance optimization.
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline orientation="horizontal" :default-value="2" :items="items" class="w-full" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline orientation="horizontal" :default-value="2" :items="items" class="w-full" />
</template>反向
使用反向道具反转时间轴的方向。
Mar 15, 2025
Project Kickoff
Kicked off the project with team alignment.
Mar 22 2025
Design Phase
User research and design workshops.
Mar 29 2025
Development Sprint
Frontend and backend development.
Apr 5 2025
Testing & Deployment
QA testing and performance optimization.
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline reverse v-model="value" orientation="vertical" :items="items" class="w-full" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { TimelineItem } from '@nuxt/ui'
const items = ref<TimelineItem[]>([
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description: 'Kicked off the project with team alignment.',
icon: 'i-lucide-rocket'
},
{
date: 'Mar 22 2025',
title: 'Design Phase',
description: 'User research and design workshops.',
icon: 'i-lucide-palette'
},
{
date: 'Mar 29 2025',
title: 'Development Sprint',
description: 'Frontend and backend development.',
icon: 'i-lucide-code'
},
{
date: 'Apr 5 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization.',
icon: 'i-lucide-check-circle'
}
])
</script>
<template>
<UTimeline reverse v-model="value" orientation="vertical" :items="items" class="w-full" />
</template>示例
控制活动项目
您可以使用default-value prop或v-model指令与项目的value来控制活动项目。如果没有提供value,则默认为索引。
Mar 15, 2025
Project Kickoff
Kicked off the project with team alignment. Set up project milestones and allocated resources.
Mar 22, 2025
Design Phase
User research and design workshops. Created wireframes and prototypes for user testing.
Mar 29, 2025
Development Sprint
Frontend and backend development. Implemented core features and integrated with APIs.
Apr 5, 2025
Testing & Deployment
QA testing and performance optimization. Deployed the application to production.
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items: TimelineItem[] = [
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description:
'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket',
value: 'kickoff'
},
{
date: 'Mar 22, 2025',
title: 'Design Phase',
description:
'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette',
value: 'design'
},
{
date: 'Mar 29, 2025',
title: 'Development Sprint',
description:
'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code',
value: 'development'
},
{
date: 'Apr 5, 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle',
value: 'deployment'
}
]
const active = ref(0)
// Note: This is for demonstration purposes only. Don't do this at home.
onMounted(() => {
setInterval(() => {
active.value = (active.value + 1) % items.length
}, 2000)
})
</script>
<template>
<UTimeline v-model="active" :items="items" class="w-96" />
</template><script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { TimelineItem } from '@nuxt/ui'
const items: TimelineItem[] = [
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description:
'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket',
value: 'kickoff'
},
{
date: 'Mar 22, 2025',
title: 'Design Phase',
description:
'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette',
value: 'design'
},
{
date: 'Mar 29, 2025',
title: 'Development Sprint',
description:
'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code',
value: 'development'
},
{
date: 'Apr 5, 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle',
value: 'deployment'
}
]
const active = ref(0)
// Note: This is for demonstration purposes only. Don't do this at home.
onMounted(() => {
setInterval(() => {
active.value = (active.value + 1) % items.length
}, 2000)
})
</script>
<template>
<UTimeline v-model="active" :items="items" class="w-96" />
</template>当提供
v-model或default-value时,使用value-key属性更改用于匹配项的键。带有选择事件
你可以添加一个@select监听器来使项目可点击。
handler函数分别接收
Event和TimelineItem作为第一个和第二个参数。Mar 15, 2025
Project Kickoff
Kicked off the project with team alignment. Set up project milestones and allocated resources.
Mar 22, 2025
Design Phase
User research and design workshops. Created wireframes and prototypes for user testing.
Mar 29, 2025
Development Sprint
Frontend and backend development. Implemented core features and integrated with APIs.
Apr 5, 2025
Testing & Deployment
QA testing and performance optimization. Deployed the application to production.
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items: TimelineItem[] = [
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description:
'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket',
value: 'kickoff'
},
{
date: 'Mar 22, 2025',
title: 'Design Phase',
description:
'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette',
value: 'design'
},
{
date: 'Mar 29, 2025',
title: 'Development Sprint',
description:
'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code',
value: 'development'
},
{
date: 'Apr 5, 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle',
value: 'deployment'
}
]
const active = ref<string | number>('kickoff')
function onSelect(_e: Event, item: TimelineItem) {
if (item.value) {
active.value = item.value
}
}
</script>
<template>
<UTimeline v-model="active" :items="items" class="w-96" @select="onSelect" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { TimelineItem } from '@nuxt/ui'
const items: TimelineItem[] = [
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
description:
'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket',
value: 'kickoff'
},
{
date: 'Mar 22, 2025',
title: 'Design Phase',
description:
'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette',
value: 'design'
},
{
date: 'Mar 29, 2025',
title: 'Development Sprint',
description:
'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code',
value: 'development'
},
{
date: 'Apr 5, 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle',
value: 'deployment'
}
]
const active = ref<string | number>('kickoff')
function onSelect(_e: Event, item: TimelineItem) {
if (item.value) {
active.value = item.value
}
}
</script>
<template>
<UTimeline v-model="active" :items="items" class="w-96" @select="onSelect" />
</template>采用交替布局
使用ui道具创建一个具有交替布局的时间轴。
Mar 15, 2025
Project Kickoff
Mar 22, 2025
Design Phase
Mar 29, 2025
Development Sprint
Apr 5, 2025
Testing & Deployment
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items: TimelineItem[] = [
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
icon: 'i-lucide-rocket',
value: 'kickoff'
},
{
date: 'Mar 22, 2025',
title: 'Design Phase',
icon: 'i-lucide-palette',
value: 'design'
},
{
date: 'Mar 29, 2025',
title: 'Development Sprint',
icon: 'i-lucide-code',
value: 'development'
},
{
date: 'Apr 5, 2025',
title: 'Testing & Deployment',
icon: 'i-lucide-check-circle',
value: 'deployment'
}
]
</script>
<template>
<UTimeline
:items="items"
:default-value="2"
:ui="{
item: 'even:flex-row-reverse even:-translate-x-[calc(100%-2rem)] rtl:even:translate-x-[calc(100%-2rem)] even:text-end'
}"
class="translate-x-[calc(50%-1rem)] rtl:-translate-x-[calc(50%-1rem)]"
/>
</template>带自定义插槽
使用slot属性可自定义特定项。
您将可以访问以下插槽:
#{{ item.slot }}-indicator#{{ item.slot }}-date#{{ item.slot }}-title#{{ item.slot }}-description
Mar 15, 2025
Project Kickoff
Kicked off the project with team alignment. Set up project milestones and allocated resources.
Mar 22, 2025
Design Phase
User research and design workshops. Created wireframes and prototypes for user testing.
Mar 29, 2025
Development Sprint

Frontend and backend development. Implemented core features and integrated with APIs.
Apr 5, 2025
Testing & Deployment
QA testing and performance optimization. Deployed the application to production.
<script setup lang="ts">
import type { TimelineItem } from '@nuxt/ui'
const items = [
{
date: 'Mar 15, 2025',
title: 'Project Kickoff',
subtitle: 'Project Initiation',
description:
'Kicked off the project with team alignment. Set up project milestones and allocated resources.',
icon: 'i-lucide-rocket',
value: 'kickoff'
},
{
date: 'Mar 22, 2025',
title: 'Design Phase',
description:
'User research and design workshops. Created wireframes and prototypes for user testing.',
icon: 'i-lucide-palette',
value: 'design'
},
{
date: 'Mar 29, 2025',
title: 'Development Sprint',
description:
'Frontend and backend development. Implemented core features and integrated with APIs.',
icon: 'i-lucide-code',
value: 'development',
slot: 'development' as const,
developers: [
{
src: 'https://github.com/J-Michalek.png',
loading: 'lazy' as const
},
{
src: 'https://github.com/benjamincanac.png',
loading: 'lazy' as const
}
]
},
{
date: 'Apr 5, 2025',
title: 'Testing & Deployment',
description: 'QA testing and performance optimization. Deployed the application to production.',
icon: 'i-lucide-check-circle',
value: 'deployment'
}
] satisfies TimelineItem[]
</script>
<template>
<UTimeline :items="items" :default-value="2" class="w-96">
<template #development-title="{ item }">
<div class="flex items-center gap-1">
<span>{{ item.title }}</span>
<UAvatarGroup size="2xs">
<UAvatar v-for="(developer, index) of item.developers" :key="index" v-bind="developer" />
</UAvatarGroup>
</div>
</template>
</UTimeline>
</template>带插槽
使用可用插槽创建更复杂的时间轴。
last year
J-Michalek opened this
last year
J-Michalek marked this pull request as ready for review
last year
benjamincanac commented on this
I've made a few changes, let me know what you think! Basically I updated the design, removed unnecessary divs, used Avatar component for the indicator since it supports icon already.
last year
J-Michalek commented on this
Looks great! Good job on cleaning it up.
last year
benjamincanac merged this
<script lang="ts" setup>
import type { TimelineItem } from '@nuxt/ui'
import { useTimeAgo } from '@vueuse/core'
const items = [
{
username: 'J-Michalek',
date: '2025-05-24T14:58:55Z',
action: 'opened this',
avatar: {
src: 'https://github.com/J-Michalek.png',
loading: 'lazy' as const
}
},
{
username: 'J-Michalek',
date: '2025-05-26T19:30:14+02:00',
action: 'marked this pull request as ready for review',
icon: 'i-lucide-check-circle'
},
{
username: 'benjamincanac',
date: '2025-05-27T11:01:20Z',
action: 'commented on this',
description:
"I've made a few changes, let me know what you think! Basically I updated the design, removed unnecessary divs, used Avatar component for the indicator since it supports icon already.",
avatar: {
src: 'https://github.com/benjamincanac.png',
loading: 'lazy' as const
}
},
{
username: 'J-Michalek',
date: '2025-05-27T11:01:20Z',
action: 'commented on this',
description: 'Looks great! Good job on cleaning it up.',
avatar: {
src: 'https://github.com/J-Michalek.png',
loading: 'lazy' as const
}
},
{
username: 'benjamincanac',
date: '2025-05-27T11:01:20Z',
action: 'merged this',
icon: 'i-lucide-git-merge'
}
] satisfies TimelineItem[]
</script>
<template>
<UTimeline
:items="items"
size="xs"
:ui="{
date: 'float-end ms-1',
description: 'px-3 py-2 ring ring-default mt-2 rounded-md text-default'
}"
class="w-96"
>
<template #title="{ item }">
<span>{{ item.username }}</span>
<span class="font-normal text-muted"> {{ item.action }}</span>
</template>
<template #date="{ item }">
{{ useTimeAgo(new Date(item.date)) }}
</template>
</UTimeline>
</template>API
Props
| Prop | Default | Type |
|---|---|---|
as | 'div' | anyThe element or component this component should render as. |
items | T[] | |
size | 'md' | "3xs" | "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" |
color | 'primary' | "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral" |
orientation | 'vertical' | "horizontal" | "vertical"The orientation of the Timeline. |
valueKey | 'value' | keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>The key used to get the value from the item. |
defaultValue | string | number | |
reverse | boolean | |
modelValue | string | number | |
ui | { root?: SlotClass; item?: SlotClass; container?: SlotClass; indicator?: SlotClass; separator?: SlotClass; wrapper?: SlotClass; date?: SlotClass; title?: SlotClass; description?: SlotClass; } |
Slots
| Slot | Type |
|---|---|
indicator | { item: T; } |
wrapper | { item: T; } |
date | { item: T; } |
title | { item: T; } |
description | { item: T; } |
Emits
| Event | Type |
|---|---|
select | [event: Event, item: T] |
update:modelValue | [value: string | number | undefined] |
Theme
app.config.ts
export default defineAppConfig({
ui: {
timeline: {
slots: {
root: 'flex gap-1.5',
item: 'group relative flex flex-1 gap-3',
container: 'relative flex items-center gap-1.5',
indicator: 'group-data-[state=completed]:text-inverted group-data-[state=active]:text-inverted text-muted',
separator: 'flex-1 rounded-full bg-elevated',
wrapper: 'w-full',
date: 'text-dimmed text-xs/5',
title: 'font-medium text-highlighted text-sm',
description: 'text-muted text-wrap text-sm'
},
variants: {
orientation: {
horizontal: {
root: 'flex-row w-full',
item: 'flex-col',
separator: 'h-0.5'
},
vertical: {
root: 'flex-col',
container: 'flex-col',
separator: 'w-0.5'
}
},
color: {
primary: {
indicator: 'group-data-[state=completed]:bg-primary group-data-[state=active]:bg-primary'
},
secondary: {
indicator: 'group-data-[state=completed]:bg-secondary group-data-[state=active]:bg-secondary'
},
success: {
indicator: 'group-data-[state=completed]:bg-success group-data-[state=active]:bg-success'
},
info: {
indicator: 'group-data-[state=completed]:bg-info group-data-[state=active]:bg-info'
},
warning: {
indicator: 'group-data-[state=completed]:bg-warning group-data-[state=active]:bg-warning'
},
error: {
indicator: 'group-data-[state=completed]:bg-error group-data-[state=active]:bg-error'
},
neutral: {
indicator: 'group-data-[state=completed]:bg-inverted group-data-[state=active]:bg-inverted'
}
},
size: {
'3xs': '',
'2xs': '',
xs: '',
sm: '',
md: '',
lg: '',
xl: '',
'2xl': '',
'3xl': ''
},
reverse: {
true: ''
}
},
compoundVariants: [
{
color: 'primary',
reverse: false,
class: {
separator: 'group-data-[state=completed]:bg-primary'
}
},
{
color: 'primary',
reverse: true,
class: {
separator: 'group-data-[state=active]:bg-primary group-data-[state=completed]:bg-primary'
}
},
{
color: 'neutral',
reverse: false,
class: {
separator: 'group-data-[state=completed]:bg-inverted'
}
},
{
color: 'neutral',
reverse: true,
class: {
separator: 'group-data-[state=active]:bg-inverted group-data-[state=completed]:bg-inverted'
}
},
{
orientation: 'horizontal',
size: '3xs',
class: {
wrapper: 'pe-4.5'
}
},
{
orientation: 'horizontal',
size: '2xs',
class: {
wrapper: 'pe-5'
}
},
{
orientation: 'horizontal',
size: 'xs',
class: {
wrapper: 'pe-5.5'
}
},
{
orientation: 'horizontal',
size: 'sm',
class: {
wrapper: 'pe-6'
}
},
{
orientation: 'horizontal',
size: 'md',
class: {
wrapper: 'pe-6.5'
}
},
{
orientation: 'horizontal',
size: 'lg',
class: {
wrapper: 'pe-7'
}
},
{
orientation: 'horizontal',
size: 'xl',
class: {
wrapper: 'pe-7.5'
}
},
{
orientation: 'horizontal',
size: '2xl',
class: {
wrapper: 'pe-8'
}
},
{
orientation: 'horizontal',
size: '3xl',
class: {
wrapper: 'pe-8.5'
}
},
{
orientation: 'vertical',
size: '3xs',
class: {
wrapper: '-mt-0.5 pb-4.5'
}
},
{
orientation: 'vertical',
size: '2xs',
class: {
wrapper: 'pb-5'
}
},
{
orientation: 'vertical',
size: 'xs',
class: {
wrapper: 'mt-0.5 pb-5.5'
}
},
{
orientation: 'vertical',
size: 'sm',
class: {
wrapper: 'mt-1 pb-6'
}
},
{
orientation: 'vertical',
size: 'md',
class: {
wrapper: 'mt-1.5 pb-6.5'
}
},
{
orientation: 'vertical',
size: 'lg',
class: {
wrapper: 'mt-2 pb-7'
}
},
{
orientation: 'vertical',
size: 'xl',
class: {
wrapper: 'mt-2.5 pb-7.5'
}
},
{
orientation: 'vertical',
size: '2xl',
class: {
wrapper: 'mt-3 pb-8'
}
},
{
orientation: 'vertical',
size: '3xl',
class: {
wrapper: 'mt-3.5 pb-8.5'
}
}
],
defaultVariants: {
size: 'md',
color: 'primary'
}
}
}
})vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
timeline: {
slots: {
root: 'flex gap-1.5',
item: 'group relative flex flex-1 gap-3',
container: 'relative flex items-center gap-1.5',
indicator: 'group-data-[state=completed]:text-inverted group-data-[state=active]:text-inverted text-muted',
separator: 'flex-1 rounded-full bg-elevated',
wrapper: 'w-full',
date: 'text-dimmed text-xs/5',
title: 'font-medium text-highlighted text-sm',
description: 'text-muted text-wrap text-sm'
},
variants: {
orientation: {
horizontal: {
root: 'flex-row w-full',
item: 'flex-col',
separator: 'h-0.5'
},
vertical: {
root: 'flex-col',
container: 'flex-col',
separator: 'w-0.5'
}
},
color: {
primary: {
indicator: 'group-data-[state=completed]:bg-primary group-data-[state=active]:bg-primary'
},
secondary: {
indicator: 'group-data-[state=completed]:bg-secondary group-data-[state=active]:bg-secondary'
},
success: {
indicator: 'group-data-[state=completed]:bg-success group-data-[state=active]:bg-success'
},
info: {
indicator: 'group-data-[state=completed]:bg-info group-data-[state=active]:bg-info'
},
warning: {
indicator: 'group-data-[state=completed]:bg-warning group-data-[state=active]:bg-warning'
},
error: {
indicator: 'group-data-[state=completed]:bg-error group-data-[state=active]:bg-error'
},
neutral: {
indicator: 'group-data-[state=completed]:bg-inverted group-data-[state=active]:bg-inverted'
}
},
size: {
'3xs': '',
'2xs': '',
xs: '',
sm: '',
md: '',
lg: '',
xl: '',
'2xl': '',
'3xl': ''
},
reverse: {
true: ''
}
},
compoundVariants: [
{
color: 'primary',
reverse: false,
class: {
separator: 'group-data-[state=completed]:bg-primary'
}
},
{
color: 'primary',
reverse: true,
class: {
separator: 'group-data-[state=active]:bg-primary group-data-[state=completed]:bg-primary'
}
},
{
color: 'neutral',
reverse: false,
class: {
separator: 'group-data-[state=completed]:bg-inverted'
}
},
{
color: 'neutral',
reverse: true,
class: {
separator: 'group-data-[state=active]:bg-inverted group-data-[state=completed]:bg-inverted'
}
},
{
orientation: 'horizontal',
size: '3xs',
class: {
wrapper: 'pe-4.5'
}
},
{
orientation: 'horizontal',
size: '2xs',
class: {
wrapper: 'pe-5'
}
},
{
orientation: 'horizontal',
size: 'xs',
class: {
wrapper: 'pe-5.5'
}
},
{
orientation: 'horizontal',
size: 'sm',
class: {
wrapper: 'pe-6'
}
},
{
orientation: 'horizontal',
size: 'md',
class: {
wrapper: 'pe-6.5'
}
},
{
orientation: 'horizontal',
size: 'lg',
class: {
wrapper: 'pe-7'
}
},
{
orientation: 'horizontal',
size: 'xl',
class: {
wrapper: 'pe-7.5'
}
},
{
orientation: 'horizontal',
size: '2xl',
class: {
wrapper: 'pe-8'
}
},
{
orientation: 'horizontal',
size: '3xl',
class: {
wrapper: 'pe-8.5'
}
},
{
orientation: 'vertical',
size: '3xs',
class: {
wrapper: '-mt-0.5 pb-4.5'
}
},
{
orientation: 'vertical',
size: '2xs',
class: {
wrapper: 'pb-5'
}
},
{
orientation: 'vertical',
size: 'xs',
class: {
wrapper: 'mt-0.5 pb-5.5'
}
},
{
orientation: 'vertical',
size: 'sm',
class: {
wrapper: 'mt-1 pb-6'
}
},
{
orientation: 'vertical',
size: 'md',
class: {
wrapper: 'mt-1.5 pb-6.5'
}
},
{
orientation: 'vertical',
size: 'lg',
class: {
wrapper: 'mt-2 pb-7'
}
},
{
orientation: 'vertical',
size: 'xl',
class: {
wrapper: 'mt-2.5 pb-7.5'
}
},
{
orientation: 'vertical',
size: '2xl',
class: {
wrapper: 'mt-3 pb-8'
}
},
{
orientation: 'vertical',
size: '3xl',
class: {
wrapper: 'mt-3.5 pb-8.5'
}
}
],
defaultVariants: {
size: 'md',
color: 'primary'
}
}
}
})
]
})Changelog
No recent changes