PricingTable (가격 테이블)
Usage
PricingTable 구성 요소는 가격책정 계획을 테이블 형식으로 표시하는 응답적이고 사용자 정의 가능한 방법을 제공하며, 데스크탑의 수평 테이블 레이아웃과 모바일의 수직 카드 레이아웃 간에 자동으로 전환하여 쉽게 비교할 수 있습니다.The PricingTable component provides a responsive and customizable way to display pricing plans in a table format, automatically switching between a horizontal table layout on desktop for easy comparison and a vertical card layout on mobile for better readability.
- 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
tiers 소품을 객체 배열로 사용하여 가격책정 계획을 정의합니다. 각 계층 객체는 다음 속성을 지원합니다.
id: string- 계층의 고유 식별자(필수)title?: string- 가격책정 계획 이름description?: string- 계획에 대한 간단한 설명price?: string- 계획의 현재 가격(예: "$99", "€99", "무료")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[]- 각 계층에서 가용성을 제공하는 기능 배열:- 각 기능에는
title및tiers객체 매핑 계층 ID가 필요합니다. - Boolean 값(
true/false)은 체크 마크(✓) 또는 빼기 아이콘(-)으로 표시됩니다. - String 값은 텍스트로 표시됩니다 (예: "무제한", "최대 5 명의 사용자").
- Numeric 값은 그대로 표시됩니다(예: 10, 100).
- 각 기능에는
- 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>examples 예제
With 슬롯 사용
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>구성요소는 다양한 슬롯 유형을 지원하여 최대의 사용자화 유연성을 제공합니다.
| 슬롯 종류 | 패턴 (Pattern) | 설명 (Description) | 예제 |
|---|---|---|---|
| Tier 슬롯 | #{tier-id}-{element} | 특정 계층 대상 | #team-title, #solo-price |
| 섹션 슬롯 | #section-{id|formatted-title}-title | 특정 섹션을 대상으로 | #section-features-title 공식 |
| 기능 slots | #feature-{id|formatted-title}-{title|value} | 특정 기능을 대상으로 지정 | #feature-developers-title |
| 일반 slots | #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>; } |
테마
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'
}
}
}
}
}
})
]
})