UIPackage

Card

Vue layout
Edit on GitHub

Bordered container with an opinionated header / content / footer layout. Use it as the wrapper around any self-contained block of content — settings panels, dashboard tiles, list cells.

Also available for React ->

Installation

$ npx shadcn-vue@latest add https://uipkge.dev/r/vue/card.json

Or with the named registry: npx shadcn-vue@latest add @uipkge/card

Examples

Props

Name Type / Values Default Required
variant
'default''elevated''outline''ghost'
optional
class HTMLAttributes['class'] optional

Dependencies

Used by

Files (9)

  • app/components/ui/card/Card.vue 0.5 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    import { cardVariants } from './card.variants'
    
    // Inlined union: SFC compiler can't extract runtime props from
    // `CardVariants['variant']`.
    const props = defineProps<{
      variant?: 'default' | 'elevated' | 'outline' | 'ghost'
      class?: HTMLAttributes['class']
    }>()
    </script>
    
    <template>
      <div data-uipkge data-slot="card" :class="cn(cardVariants({ variant }), 'overflow-hidden', props.class)">
        <slot />
      </div>
    </template>
  • app/components/ui/card/CardAction.vue 0.4 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
    }>()
    </script>
    
    <template>
      <div
        data-uipkge
        data-slot="card-action"
        :class="cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', props.class)"
      >
        <slot />
      </div>
    </template>
  • app/components/ui/card/CardContent.vue 0.3 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
    }>()
    </script>
    
    <template>
      <div data-uipkge data-slot="card-content" :class="cn('p-6 pt-0', props.class)">
        <slot />
      </div>
    </template>
  • app/components/ui/card/CardDescription.vue 0.3 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
    }>()
    </script>
    
    <template>
      <p data-uipkge data-slot="card-description" :class="cn('text-muted-foreground text-sm', props.class)">
        <slot />
      </p>
    </template>
  • app/components/ui/card/CardFooter.vue 0.3 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
    }>()
    </script>
    
    <template>
      <div data-uipkge data-slot="card-footer" :class="cn('flex items-center p-6 pt-0', props.class)">
        <slot />
      </div>
    </template>
  • app/components/ui/card/CardHeader.vue 0.3 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
    }>()
    </script>
    
    <template>
      <div data-uipkge data-slot="card-header" :class="cn('flex flex-col space-y-1.5 p-6', props.class)">
        <slot />
      </div>
    </template>
  • app/components/ui/card/CardTitle.vue 0.4 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<{
      as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div'
      class?: HTMLAttributes['class']
    }>()
    </script>
    
    <template>
      <component
        :is="props.as ?? 'h3'"
        data-uipkge
        data-slot="card-title"
        :class="cn('leading-none font-semibold tracking-tight', props.class)"
      >
        <slot />
      </component>
    </template>
  • app/components/ui/card/card.variants.ts 1 kB
    import type { VariantProps } from 'class-variance-authority'
    import { cva } from 'class-variance-authority'
    
    /**
     * Variant definitions live in their own file (rather than the package
     * `index.ts`) so `Card.vue` can `import { cardVariants } from './card.variants'`
     * without creating a circular dependency back through the index. The circular
     * form caused intermittent `$setup.cardVariants is not a function` errors
     * during dev SSR when several `<Card>` instances rendered in a v-for before
     * the module graph had fully resolved.
     */
    export const cardVariants = cva(
      'bg-card text-card-foreground rounded-xl border shadow-sm transition-colors duration-150',
      {
        variants: {
          variant: {
            default: 'border-border',
            elevated: 'border-transparent shadow-md hover:shadow-md',
            outline: 'border-2',
            ghost: 'border-transparent shadow-none hover:bg-muted/50',
          },
        },
        defaultVariants: {
          variant: 'default',
        },
      },
    )
    
    export type CardVariants = VariantProps<typeof cardVariants>
  • app/components/ui/card/index.ts 0.6 kB
    export { default as Card } from './Card.vue'
    export { default as CardAction } from './CardAction.vue'
    export { default as CardContent } from './CardContent.vue'
    export { default as CardDescription } from './CardDescription.vue'
    export { default as CardFooter } from './CardFooter.vue'
    export { default as CardHeader } from './CardHeader.vue'
    export { default as CardTitle } from './CardTitle.vue'
    
    // Re-export variant API from the sibling file (kept separate to avoid the
    // Card.vue <-> index.ts circular import that broke dev SSR).
    export { cardVariants, type CardVariants } from './card.variants'

Raw manifest: https://uipkge.dev/r/vue/card.json