PriceTable
Utilisation
Le composant PricingTable fournit un moyen réactif et personnalisable d'afficher les plans de tarification dans un format de tableau, basculant automatiquement entre une disposition de tableau horizontal sur le bureau pour une comparaison facile et une disposition de carte verticale sur mobile pour une meilleure lisibilité.
- SoloMost popularFor indie hackers.$249billed annually/monthFeaturesNumber of developers1ProjectsGitHub repository accessUpdatesPatch & minorSupportCommunitySecuritySSOAudit logsCustom security review
- TeamFor growing teams.$499billed annually/monthFeaturesNumber of developers5ProjectsGitHub repository accessUpdatesAll updatesSupportPrioritySecuritySSOAudit logsCustom security review
- EnterpriseFor large organizations.CustomFeaturesNumber of developersUnlimitedProjectsGitHub repository accessUpdatesAll updatesSupport24/7SecuritySSOAudit logsCustom security review
Tiers
Utilisez le prop tiers comme un tableau d'objets pour définir vos plans de tarification. Chaque objet de niveau prend en charge les propriétés suivantes:
id: string-Identifiant unique du niveau (obligatoire)title?: string-Nom du plan de tarificationdescription?: string-Brève description du planprice?: string-Le prix actuel du forfait (par exemple,"$99","€ 99","Gratuit")discount?: string-Le prix réduit qui affichera lepriceavec barré (par exemple,"$79","€ 79")billingCycle?: string-La période de prix unitaire qui apparaît à côté du prix (par exemple,"/mois","/siège/mois")billingPeriod?: string-Contexte de facturation supplémentaire qui apparaît au-dessus du cycle de facturation (par exemple,"facturé mensuellement")badge?: string | BadgeProps-Afficher un badge à côté du titre{ color: 'primary', variant: 'subtle' }button?: ButtonProps-Configurer le bouton CTA{ size: 'lg', block: true }highlight?: boolean-Souligner visuellement ce niveau comme option recommandée
- SoloMost popularFor indie hackers.$249billed annually/month
- TeamFor growing teams.$499billed annually/month
- EnterpriseFor large organizations.Custom
<script setup lang="ts">
import type { PricingTableTier } from '@nuxt/ui'
const tiers = ref<PricingTableTier[]>([
{
id: 'solo',
title: 'Solo',
description: 'For indie hackers.',
price: '$249',
billingCycle: '/month',
billingPeriod: 'billed annually',
badge: 'Most popular',
button: {
label: 'Buy now',
variant: 'subtle'
}
},
{
id: 'team',
title: 'Team',
description: 'For growing teams.',
price: '$499',
billingCycle: '/month',
billingPeriod: 'billed annually',
button: {
label: 'Buy now'
},
highlight: true
},
{
id: 'enterprise',
title: 'Enterprise',
description: 'For large organizations.',
price: 'Custom',
button: {
label: 'Contact sales',
color: 'neutral'
}
}
])
</script>
<template>
<UPricingTable :tiers="tiers" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { PricingTableTier } from '@nuxt/ui'
const tiers = ref<PricingTableTier[]>([
{
id: 'solo',
title: 'Solo',
description: 'For indie hackers.',
price: '$249',
billingCycle: '/month',
billingPeriod: 'billed annually',
badge: 'Most popular',
button: {
label: 'Buy now',
variant: 'subtle'
}
},
{
id: 'team',
title: 'Team',
description: 'For growing teams.',
price: '$499',
billingCycle: '/month',
billingPeriod: 'billed annually',
button: {
label: 'Buy now'
},
highlight: true
},
{
id: 'enterprise',
title: 'Enterprise',
description: 'For large organizations.',
price: 'Custom',
button: {
label: 'Contact sales',
color: 'neutral'
}
}
])
</script>
<template>
<UPricingTable :tiers="tiers" />
</template>Sections
Utilisez la prop sections pour organiser les fonctionnalités en groupes logiques. Chaque section représente une catégorie de fonctionnalités que vous souhaitez comparer entre différents niveaux de tarification.
title: string-L'en-tête de la section des fonctionnalitésfeatures: PricingTableSectionFeature[]-Une gamme de fonctionnalités avec leur disponibilité dans chaque niveau:- Chaque fonctionnalité nécessite un identifiant de niveau de mappage d'objet
titleettiersaux valeurs - Les valeurs booléennes (
true/false) s'affichent sous forme de coche (✓) ou de moins (-). - String values will be displayed as text (e.g."Unlimited","Up to 5 users")
- Les valeurs numériques seront affichées telles quelles (par exemple, 10, 100)
- Chaque fonctionnalité nécessite un identifiant de niveau de mappage d'objet
- SoloFor indie hackers.$249/monthFeaturesNumber of developers1ProjectsSecuritySSO
- TeamFor growing teams.$499/monthFeaturesNumber of developers5ProjectsSecuritySSO
- EnterpriseFor large organizations.CustomFeaturesNumber of developersUnlimitedProjectsSecuritySSO
<script setup lang="ts">
import type { PricingTableTier, PricingTableSection } from '@nuxt/ui'
const tiers = ref<PricingTableTier[]>([
{
id: 'solo',
title: 'Solo',
price: '$249',
description: 'For indie hackers.',
billingCycle: '/month',
button: {
label: 'Buy now',
variant: 'subtle'
}
},
{
id: 'team',
title: 'Team',
price: '$499',
description: 'For growing teams.',
billingCycle: '/month',
button: {
label: 'Buy now'
}
},
{
id: 'enterprise',
title: 'Enterprise',
price: 'Custom',
description: 'For large organizations.',
button: {
label: 'Contact sales',
color: 'neutral'
}
}
])
const sections = ref<PricingTableSection[]>([
{
title: 'Features',
features: [
{
title: 'Number of developers',
tiers: {
solo: '1',
team: '5',
enterprise: 'Unlimited'
}
},
{
title: 'Projects',
tiers: {
solo: true,
team: true,
enterprise: true
}
}
]
},
{
title: 'Security',
features: [
{
title: 'SSO',
tiers: {
solo: false,
team: true,
enterprise: true
}
}
]
}
])
</script>
<template>
<UPricingTable :tiers="tiers" :sections="sections" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { PricingTableTier, PricingTableSection } from '@nuxt/ui'
const tiers = ref<PricingTableTier[]>([
{
id: 'solo',
title: 'Solo',
price: '$249',
description: 'For indie hackers.',
billingCycle: '/month',
button: {
label: 'Buy now',
variant: 'subtle'
}
},
{
id: 'team',
title: 'Team',
price: '$499',
description: 'For growing teams.',
billingCycle: '/month',
button: {
label: 'Buy now'
}
},
{
id: 'enterprise',
title: 'Enterprise',
price: 'Custom',
description: 'For large organizations.',
button: {
label: 'Contact sales',
color: 'neutral'
}
}
])
const sections = ref<PricingTableSection[]>([
{
title: 'Features',
features: [
{
title: 'Number of developers',
tiers: {
solo: '1',
team: '5',
enterprise: 'Unlimited'
}
},
{
title: 'Projects',
tiers: {
solo: true,
team: true,
enterprise: true
}
}
]
},
{
title: 'Security',
features: [
{
title: 'SSO',
tiers: {
solo: false,
team: true,
enterprise: true
}
}
]
}
])
</script>
<template>
<UPricingTable :tiers="tiers" :sections="sections" />
</template>Exemples
Avec slots
Le composant PricingTable fournit de puissantes options de personnalisation des emplacements pour personnaliser l'affichage de votre contenu. Vous pouvez personnaliser des éléments individuels à l'aide d'emplacements génériques ou cibler des éléments spécifiques à l'aide de leurs ID.
- SoloFor indie hackers.$249/monthFeaturesNumber of developers1ProjectsSecuritySSO
- TeamFor growing teams.$499/monthFeaturesNumber of developers5ProjectsSecuritySSO
- EnterpriseFor large organizations.CustomFeaturesNumber of developersUnlimitedProjectsSecuritySSO
<script setup lang="ts">
const tiers = [
{
id: 'solo',
title: 'Solo',
price: '$249',
description: 'For indie hackers.',
billingCycle: '/month',
button: { label: 'Buy now', variant: 'subtle' as const }
},
{
id: 'team',
title: 'Team',
price: '$499',
description: 'For growing teams.',
billingCycle: '/month',
button: { label: 'Buy now' },
highlight: true
},
{
id: 'enterprise',
title: 'Enterprise',
price: 'Custom',
description: 'For large organizations.',
button: { label: 'Contact sales', color: 'neutral' as const }
}
]
const sections = [
{
id: 'features',
title: 'Features',
features: [
{
id: 'developers',
title: 'Number of developers',
tiers: { solo: '1', team: '5', enterprise: 'Unlimited' }
},
{
id: 'projects',
title: 'Projects',
tiers: { solo: true, team: true, enterprise: true }
}
]
},
{
id: 'security',
title: 'Security',
features: [
{
title: 'SSO',
tiers: { solo: false, team: true, enterprise: true }
}
]
}
]
</script>
<template>
<UPricingTable :tiers="tiers" :sections="sections">
<!-- Customize specific tier title -->
<template #team-title="{ tier }">
<div class="flex items-center gap-2">
<UIcon name="i-lucide-crown" class="size-4 text-amber-500" />
{{ tier.title }}
</div>
</template>
<!-- Customize specific section title -->
<template #section-security-title="{ section }">
<div class="flex items-center gap-2">
<UIcon name="i-lucide-shield-check" class="size-4 text-green-500" />
<span class="font-semibold text-green-700">{{ section.title }}</span>
</div>
</template>
<!-- Customize specific feature value -->
<template #feature-developers-value="{ feature, tier }">
<template v-if="feature.tiers?.[tier.id]">
<UBadge :label="String(feature.tiers[tier.id])" color="primary" variant="soft" />
</template>
<UIcon v-else name="i-lucide-x" class="size-4 text-muted" />
</template>
</UPricingTable>
</template>Le composant prend en charge différents types de fentes pour une flexibilité de personnalisation maximale:
| Type de slot | Pattern | Description | exemple |
|---|---|---|---|
| Tier slots | #{tier-id}-{element} | Cible spécifique Tiers | Xph236x et Xph237x |
| Section slots | #section-{id|formatted-title}-title | Sections ciblées spécifiques | #section-features-title and |
| Feature slots | #feature-{id|formatted-title}-{title|value} and | Caractéristiques spécifiques cibles | #feature-developers-title |
| Générique slots | #tier-title, #section-title, etc. | Applicable à tous les items | #feature-value |
id n'est fourni, le nom de la machine à sous est généré automatiquement à partir du titre (par exemple,"Premium Features!" devient #section-premium-features-title).API
Props
| Prop | Default | Type |
|---|---|---|
as | 'div' | anyThe element or component this component should render as. |
tiers | T[]The pricing tiers to display in the table. Each tier represents a pricing plan with its own title, description, price, and features. | |
sections | PricingTableSection<T>[]The sections of features to display in the table. Each section contains a title and a list of features with their availability in each tier. | |
caption | t('pricingTable.caption') | stringThe caption to display above the table. |
ui | { root?: SlotClass; table?: SlotClass; list?: SlotClass; item?: SlotClass; caption?: SlotClass; thead?: SlotClass; tbody?: SlotClass; tr?: SlotClass; th?: SlotClass; td?: SlotClass; tier?: SlotClass; tierWrapper?: SlotClass; tierTitleWrapper?: SlotClass; tierTitle?: SlotClass; tierDescription?: SlotClass; tierBadge?: SlotClass; tierPriceWrapper?: SlotClass; tierPrice?: SlotClass; tierDiscount?: SlotClass; tierBilling?: SlotClass; tierBillingPeriod?: SlotClass; tierBillingCycle?: SlotClass; tierButton?: SlotClass; tierFeatureIcon?: SlotClass; section?: SlotClass; sectionTitle?: SlotClass; feature?: SlotClass; featureTitle?: SlotClass; featureValue?: SlotClass; } |
Slots
| Slot | Type |
|---|---|
caption | {} |
tier | { tier: T; } |
tier-title | { tier: T; } |
tier-description | { tier: T; } |
tier-badge | { tier: T; } |
tier-button | { tier: T; } |
tier-billing | { tier: T; } |
tier-discount | { tier: T; } |
tier-price | { tier: T; } |
section-title | { section: PricingTableSection<T>; } |
feature-title | { feature: PricingTableSectionFeature<T>; section: PricingTableSection<T>; } |
feature-value | { feature: PricingTableSectionFeature<T>; tier: T; section: PricingTableSection<T>; } |
Thème
export default defineAppConfig({
ui: {
pricingTable: {
slots: {
root: 'w-full relative',
table: 'w-full table-fixed border-separate border-spacing-x-0 hidden md:table h-fit',
list: 'md:hidden flex flex-col gap-6 w-full',
item: 'p-6 flex flex-col border border-default rounded-lg',
caption: 'sr-only',
thead: '',
tbody: '',
tr: '',
th: 'py-4 font-normal text-start border-b border-default',
td: 'px-6 py-4 text-center border-b border-default',
tier: 'p-6 text-start font-normal align-top h-full',
tierWrapper: 'flex flex-col md:h-full',
tierTitleWrapper: 'flex items-center gap-3',
tierTitle: 'text-lg font-semibold text-highlighted',
tierDescription: 'text-sm font-normal text-muted mt-1',
tierBadge: 'truncate',
tierPriceWrapper: 'flex items-center gap-1 mt-4',
tierPrice: 'text-highlighted text-3xl sm:text-4xl font-semibold',
tierDiscount: 'text-muted line-through text-xl sm:text-2xl',
tierBilling: 'flex flex-col justify-between min-w-0',
tierBillingPeriod: 'text-toned truncate text-xs font-medium',
tierBillingCycle: 'text-muted truncate text-xs font-medium',
tierButton: 'mt-6 md:mt-auto md:pt-6',
tierFeatureIcon: 'size-5 shrink-0',
section: 'mt-6 flex flex-col gap-2',
sectionTitle: 'font-semibold text-sm text-highlighted',
feature: 'flex items-center justify-between gap-1',
featureTitle: 'text-sm text-default',
featureValue: 'text-sm text-muted flex justify-center min-w-5'
},
variants: {
section: {
true: {
tr: '*:pt-8'
}
},
active: {
true: {
tierFeatureIcon: 'text-primary'
}
},
highlight: {
true: {
tier: 'bg-elevated/50 border-x border-t border-default rounded-t-lg',
td: 'bg-elevated/50 border-x border-default',
item: 'bg-elevated/50'
}
}
}
}
}
})import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
pricingTable: {
slots: {
root: 'w-full relative',
table: 'w-full table-fixed border-separate border-spacing-x-0 hidden md:table h-fit',
list: 'md:hidden flex flex-col gap-6 w-full',
item: 'p-6 flex flex-col border border-default rounded-lg',
caption: 'sr-only',
thead: '',
tbody: '',
tr: '',
th: 'py-4 font-normal text-start border-b border-default',
td: 'px-6 py-4 text-center border-b border-default',
tier: 'p-6 text-start font-normal align-top h-full',
tierWrapper: 'flex flex-col md:h-full',
tierTitleWrapper: 'flex items-center gap-3',
tierTitle: 'text-lg font-semibold text-highlighted',
tierDescription: 'text-sm font-normal text-muted mt-1',
tierBadge: 'truncate',
tierPriceWrapper: 'flex items-center gap-1 mt-4',
tierPrice: 'text-highlighted text-3xl sm:text-4xl font-semibold',
tierDiscount: 'text-muted line-through text-xl sm:text-2xl',
tierBilling: 'flex flex-col justify-between min-w-0',
tierBillingPeriod: 'text-toned truncate text-xs font-medium',
tierBillingCycle: 'text-muted truncate text-xs font-medium',
tierButton: 'mt-6 md:mt-auto md:pt-6',
tierFeatureIcon: 'size-5 shrink-0',
section: 'mt-6 flex flex-col gap-2',
sectionTitle: 'font-semibold text-sm text-highlighted',
feature: 'flex items-center justify-between gap-1',
featureTitle: 'text-sm text-default',
featureValue: 'text-sm text-muted flex justify-center min-w-5'
},
variants: {
section: {
true: {
tr: '*:pt-8'
}
},
active: {
true: {
tierFeatureIcon: 'text-primary'
}
},
highlight: {
true: {
tier: 'bg-elevated/50 border-x border-t border-default rounded-t-lg',
td: 'bg-elevated/50 border-x border-default',
item: 'bg-elevated/50'
}
}
}
}
}
})
]
})