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.

  • Solo
    Most popular
    For indie hackers.
    $249
    billed annually/month
    Features
    Number of developers
    1
    Projects
    GitHub repository access
    Updates
    Patch & minor
    Support
    Community
    Security
    SSO
    Audit logs
    Custom security review
  • Team
    For growing teams.
    $499
    billed annually/month
    Features
    Number of developers
    5
    Projects
    GitHub repository access
    Updates
    All updates
    Support
    Priority
    Security
    SSO
    Audit logs
    Custom security review
  • Enterprise
    For large organizations.
    Custom
    Features
    Number of developers
    Unlimited
    Projects
    GitHub repository access
    Updates
    All updates
    Support
    24/7
    Security
    SSO
    Audit logs
    Custom 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 - 이 계층을 권장 옵션으로 시각적으로 강조할지 여부
  • Solo
    Most popular
    For indie hackers.
    $249
    billed annually/month
  • Team
    For growing teams.
    $499
    billed annually/month
  • Enterprise
    For 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).
  • Solo
    For indie hackers.
    $249
     /month
    Features
    Number of developers
    1
    Projects
    Security
    SSO
  • Team
    For growing teams.
    $499
     /month
    Features
    Number of developers
    5
    Projects
    Security
    SSO
  • Enterprise
    For large organizations.
    Custom
    Features
    Number of developers
    Unlimited
    Projects
    Security
    SSO
<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를 사용하여 특정 항목을 대상으로 지정할 수 있습니다.

  • Solo
    For indie hackers.
    $249
     /month
    Features
    Number of developers
    1
    Projects
    Security
    SSO
  • Team
    For growing teams.
    $499
     /month
    Features
    Number of developers
    5
    Projects
    Security
    SSO
  • Enterprise
    For large organizations.
    Custom
    Features
    Number of developers
    Unlimited
    Projects
    Security
    SSO
<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'
any

The 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')
string

The 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>; }

테마

app.config.ts
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'
          }
        }
      }
    }
  }
})
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: {
        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'
              }
            }
          }
        }
      }
    })
  ]
})

변경 로그

No recent changes