PricingTable
使用法
PricingTableコンポーネントは、テーブル形式で価格プランを表示するための応答性とカスタマイズ性の高い方法を提供します。比較しやすいデスクトップ上の水平のテーブルレイアウトと、読みやすいモバイル上の垂直のカードライアウトを自動的に切り替えます。
- 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
Tier
tiersプロパティをオブジェクトの配列として使用して、料金プランを定義します。各階層オブジェクトは以下のプロパティをサポートします。
id: string—階層の一意の識別子(必須)title?: string—料金プラン名description?: string—プランの簡単な説明price?: string—プランの現在の価格(例:"$99"、"€ 99"、"Free")discount?: string—priceがストライクスルー付きで表示される割引価格例"$79""€ 79"billingCycle?: string—価格の横に表示される単価期間(例:"/month"、"/seat/month")billingPeriod?: string—請求サイクルの上に表示される追加の請求コンテキスト(例:“毎月請求”)。badge?: string | BadgeProps—タイトル{ color: 'primary', variant: 'subtle' }の横にバッジを表示するbutton?: ButtonProps—CTAボタンの設定{ size: 'lg', block: true }highlight?: boolean—推奨オプションとしてこの階層を視覚的に強調するかどうか
- 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プロパティを使用して、機能を論理グループに編成します。各セクションは、異なる価格帯で比較したい機能のカテゴリを表します。
title: string—フィーチャーセクションの見出しfeatures: PricingTableSectionFeature[]—各階層で利用可能な機能の配列:- 各機能には、階層IDを値にマッピングする
titleとtiersオブジェクトが必要です。 - Boolean値
true/falseはチェックマーク✓またはマイナスアイコン—として表示されます。 - Stringの値はテキストとして表示されます例"Unlimited""Max to 5 users"
- 数値はそのまま表示されます(例:10、100)
- 各機能には、階層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">
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>サンプル
スロット付き
PricingTableコンポーネントは、コンテンツの表示を調整するための強力なスロットカスタマイズオプションを提供します。汎用スロットを使用して個々の要素をカスタマイズしたり、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>カスタマイズの柔軟性を最大限に高めるため、さまざまなスロットタイプをサポート。
| スロットタイプ | パターン | 説明 | 例 |
|---|---|---|---|
| Tierスロット | #{tier-id}-{element} | ターゲット特定階層 | #team-title、#solo-price |
| セクションスロット | #section-{id|formatted-title}-title | 対象セクション | #section-features-title |
| フィーチャースロット | #feature-{id|formatted-title}-{title|value} | ターゲット固有の機能 | #feature-developers-title |
| 汎用スロット | #tier-title、#section-titleなど | すべての項目に適用 | #feature-value |
idが指定されていない場合、スロット名はタイトルから自動生成されます(例:“Premium Features!”は#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; } |
スロット
| 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>; } |
Theme
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'
}
}
}
}
}
})
]
})