Skip to main content
PolyUI/docs

基础组件

Card 卡片

通用内容容器,包含 Header / Title / Description / Content / Footer 子组件。

安装

bash
npx polyui add card

登录

Login to your account
Enter your email below to login to your account

Don't have an account?  

tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@polyui/react/card"
import { Button } from "@polyui/react/button"
import { Input } from "@polyui/react/input"
import { Label } from "@polyui/react/label"
export function CardLogin() {
  return (
    <Card className="w-full max-w-md">
      <CardHeader>
        <CardTitle>Login to your account</CardTitle>
        <CardDescription>Enter your email below to login to your account</CardDescription>
      </CardHeader>
      <CardContent>
        <form>
          <div className="flex flex-col gap-4">
            <div className="grid gap-2">
              <Label htmlFor="email">Email</Label>
              <Input id="email" type="email" placeholder="m@example.com" />
            </div>
            <div className="grid gap-2">
              <div className="flex items-center">
                <Label htmlFor="password">Password</Label>
                <Button variant="link" size="xs" className="ml-auto h-auto p-0 text-sm">
                  Forgot your password?
                </Button>
              </div>
              <Input id="password" type="password" />
            </div>
          </div>
        </form>
      </CardContent>
      <CardFooter className="flex-col gap-2">
        <Button type="submit" className="w-full">
          Login
        </Button>
        <Button variant="outline" className="w-full">
          Continue with Google
        </Button>
        <p className="mt-2 text-center text-sm text-muted-foreground">
          Don&apos;t have an account? &nbsp;
          <Button variant="link" size="xs" className="h-auto p-0">
            Sign up
          </Button>
        </p>
      </CardFooter>
    </Card>
  )
}

会议记录

Meeting Notes
Transcript from the meeting with the client.

Client requested dashboard redesign with focus on mobile responsiveness.

  1. New analytics widgets for daily/weekly metrics
  2. Simplified navigation menu
  3. Dark mode support
  4. Timeline: 6 weeks
  5. Follow-up meeting scheduled for next Tuesday
OS
HL
HR
JW
tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@polyui/react/card"
export function CardMeetingNotes() {
  return (
    <Card className="max-w-md">
      <CardHeader>
        <CardTitle>Meeting Notes</CardTitle>
        <CardDescription>Transcript from the meeting with the client.</CardDescription>
      </CardHeader>
      <CardContent className="text-sm">
        <p>Client requested dashboard redesign with focus on mobile responsiveness.</p>
        <ol className="mt-4 flex list-decimal flex-col gap-2 pl-6">
          <li>New analytics widgets for daily/weekly metrics</li>
          <li>Simplified navigation menu</li>
          <li>Dark mode support</li>
          <li>Timeline: 6 weeks</li>
          <li>Follow-up meeting scheduled for next Tuesday</li>
        </ol>
      </CardContent>
      <CardFooter>
        <div className="flex -space-x-2 hover:space-x-1">
          {["OS", "HL", "HR", "JW"].map((initials) => (
            <div
              key={initials}
              className="flex size-8 items-center justify-center rounded-full bg-muted text-xs font-medium ring-2 ring-background transition-all duration-300"
            >
              {initials}
            </div>
          ))}
        </div>
      </CardFooter>
    </Card>
  )
}

邀请成员

Team Members
Invite Member
JA
Jimmy AndrosonUI Designer
DA
Dean AmbroseUX Designer
AJ
Anita JohnBranding
tsx
import { Card, CardHeader, CardTitle, CardContent } from "@polyui/react/card"
import { CircleFadingPlusIcon } from "lucide-react"
export function CardInviteMembers() {
  return (
    <Card className="w-full max-w-lg">
      <CardHeader>
        <CardTitle>Team Members</CardTitle>
      </CardHeader>
      <CardContent className="grid gap-4 sm:grid-cols-2">
        <div className="flex items-center gap-4">
          <CircleFadingPlusIcon />
          <span className="text-sm font-semibold">Invite Member</span>
        </div>
        {inviteMembers.map((m) => (
          <div key={m.initials} className="flex items-center gap-4">
            <div className="flex size-10 items-center justify-center rounded-full bg-muted text-xs font-medium">
              {m.initials}
            </div>
            <div className="flex flex-col">
              <span className="text-sm font-semibold">{m.name}</span>
              <span className="text-muted-foreground text-sm">{m.role}</span>
            </div>
          </div>
        ))}
      </CardContent>
    </Card>
  )
}

底部图片

Fluid Gradient Flow
A vibrant and abstract background with smooth gradient curves.
Fluid Gradient Flow
tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@polyui/react/card"
export function CardBottomImage() {
  return (
    <Card className="max-w-md pb-0">
      <CardHeader>
        <CardTitle>Fluid Gradient Flow</CardTitle>
        <CardDescription>A vibrant and abstract background with smooth gradient curves.</CardDescription>
      </CardHeader>
      <CardContent className="px-0">
        <img
          src="https://cdn.shadcnstudio.com/ss-assets/components/card/image-1.png?height=280&format=auto"
          alt="Fluid Gradient Flow"
          className="aspect-video h-64 w-full rounded-b-xl object-cover"
        />
      </CardContent>
    </Card>
  )
}

顶部图片

Ethereal Swirl Gradient
Ethereal Swirl Gradient
Smooth, flowing gradients blending rich reds and blues in an abstract swirl.
tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@polyui/react/card"
import { Button } from "@polyui/react/button"
export function CardTopImage() {
  return (
    <Card className="max-w-md pt-0">
      <CardContent className="px-0">
        <img
          src="https://cdn.shadcnstudio.com/ss-assets/components/card/image-2.png?height=280&format=auto"
          alt="Ethereal Swirl Gradient"
          className="aspect-video h-64 w-full rounded-t-xl object-cover"
        />
      </CardContent>
      <CardHeader>
        <CardTitle>Ethereal Swirl Gradient</CardTitle>
        <CardDescription>Smooth, flowing gradients blending rich reds and blues in an abstract swirl.</CardDescription>
      </CardHeader>
      <CardFooter className="gap-3 max-sm:flex-col max-sm:items-stretch">
        <Button>Explore More</Button>
        <Button variant="outline">Download Now</Button>
      </CardFooter>
    </Card>
  )
}

水平

Dreamy Colorwave Gradient
Dreamy Colorwave Gradient
A smooth blend of vibrant pinks, purples, and blues for a magical touch.
tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@polyui/react/card"
import { Button } from "@polyui/react/button"
export function CardHorizontal() {
  return (
    <Card className="max-w-lg py-0 sm:flex-row sm:gap-0">
      <CardContent className="grow px-0">
        <img
          src="https://cdn.shadcnstudio.com/ss-assets/components/card/image-3.png"
          alt="Dreamy Colorwave Gradient"
          className="size-full rounded-l-xl object-cover"
        />
      </CardContent>
      <div className="sm:min-w-52">
        <CardHeader className="pt-6">
          <CardTitle>Dreamy Colorwave Gradient</CardTitle>
          <CardDescription>A smooth blend of vibrant pinks, purples, and blues for a magical touch.</CardDescription>
        </CardHeader>
        <CardFooter className="gap-3 py-6">
          <Button className="bg-gradient-to-br from-purple-500 to-pink-500 text-white">Explore More</Button>
        </CardFooter>
      </div>
    </Card>
  )
}

遮罩

Creative Catalyst
Creative Catalyst

Step into a world where imagination takes the lead and every pixel tells a story.

tsx
import { Card, CardTitle, CardContent } from "@polyui/react/card"
export function CardOverlay() {
  return (
    <Card className="relative max-w-md py-0 before:absolute before:inset-0 before:rounded-xl before:bg-primary/70">
      <CardContent className="px-0">
        <img
          src="https://cdn.shadcnstudio.com/ss-assets/components/card/image-8.png?width=448&height=280&format=auto"
          alt="Creative Catalyst"
          className="h-64 w-full rounded-xl object-cover"
        />
      </CardContent>
      <div className="absolute inset-0 flex flex-col justify-start pt-6 px-6">
        <CardTitle className="text-primary-foreground">Creative Catalyst</CardTitle>
        <p className="mt-2 text-sm text-primary-foreground/80">
          Step into a world where imagination takes the lead and every pixel tells a story.
        </p>
      </div>
    </Card>
  )
}

柔和描边

Design Throwdown
Where passion, pressure, and pixels collide—push your creativity to the edge and show what you are made of.
Creative Clash
Step into a space where design skills are tested, ideas come alive, and only the boldest concepts win.
tsx
import { Card, CardHeader, CardTitle, CardContent } from "@polyui/react/card"
export function CardSoftOutline() {
  return (
    <div className="flex flex-wrap gap-4">
      <Card className="bg-primary/20 max-w-md gap-0">
        <CardHeader>
          <CardTitle>Design Throwdown</CardTitle>
        </CardHeader>
        <CardContent className="text-sm text-muted-foreground">
          Where passion, pressure, and pixels collide—push your creativity to the edge and show what you are made of.
        </CardContent>
      </Card>
      <Card className="border-primary max-w-md gap-0 bg-transparent shadow-none">
        <CardHeader>
          <CardTitle>Creative Clash</CardTitle>
        </CardHeader>
        <CardContent className="text-sm text-muted-foreground">
          Step into a space where design skills are tested, ideas come alive, and only the boldest concepts win.
        </CardContent>
      </Card>
    </div>
  )
}

带标签页

Welcome to the Home tab! Here, you can explore the latest updates, news, and highlights.

tsx
import { useState } from "react"
import { Card, CardContent } from "@polyui/react/card"
import { cn } from "@polyui/core/lib/utils"
export function CardWithTabs() {
  const [activeTab, setActiveTab] = useState("home")
  return (
    <Card className="w-fit">
      <CardContent>
        <div className="w-full max-w-sm">
          <div className="flex border-b">
            {tabItems.map((tab) => (
              <button
                key={tab.value}
                onClick={() => setActiveTab(tab.value)}
                className={cn(
                  "h-10 px-4 text-sm transition-colors",
                  activeTab === tab.value
                    ? "border-b-2 border-primary font-medium text-foreground"
                    : "text-muted-foreground hover:text-foreground"
                )}
              >
                {tab.name}
              </button>
            ))}
          </div>
          <p className="p-4 text-sm text-muted-foreground">{tabItems.find((t) => t.value === activeTab)?.content}</p>
        </div>
      </CardContent>
    </Card>
  )
}

推文卡片

PG
Philip George
@philip20
Post image

Lost in the colors of the night 🌌✨ — every gradient tells a story worth exploring.

tsx
import { useState } from "react"
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, CardAction } from "@polyui/react/card"
import { Button } from "@polyui/react/button"
import { HeartIcon, MessageCircleIcon, RepeatIcon, SendIcon, UserPlusIcon, EllipsisIcon, BadgeCheckIcon } from "lucide-react"
import { cn } from "@polyui/core/lib/utils"
export function CardTweet() {
  const [liked, setLiked] = useState(true)
  return (
    <Card className="max-w-md">
      <CardHeader className="flex items-center justify-between gap-3">
        <div className="flex items-center gap-3">
          <div className="flex size-10 items-center justify-center rounded-full bg-muted text-xs font-medium ring-2 ring-ring">
            PG
          </div>
          <div className="flex flex-col gap-0.5">
            <CardTitle className="flex items-center gap-1 text-sm">
              Philip George <BadgeCheckIcon className="size-4 fill-sky-600 stroke-white dark:fill-sky-400" />
            </CardTitle>
            <CardDescription>@philip20</CardDescription>
          </div>
        </div>
        <CardAction>
          <div className="flex items-center gap-2">
            <Button variant="outline" size="sm">
              <UserPlusIcon />
              Follow
            </Button>
            <Button variant="ghost" size="icon-sm" aria-label="Toggle menu">
              <EllipsisIcon />
            </Button>
          </div>
        </CardAction>
      </CardHeader>
      <CardContent className="space-y-4 text-sm">
        <img
          src="https://cdn.shadcnstudio.com/ss-assets/components/card/image-6.png?width=350&format=auto"
          alt="Post image"
          className="aspect-video w-full rounded-md object-cover"
        />
        <p>Lost in the colors of the night 🌌✨ — every gradient tells a story worth exploring.</p>
      </CardContent>
      <CardFooter className="flex items-center gap-1">
        <Button variant="ghost" size="sm" onClick={() => setLiked(!liked)}>
          <HeartIcon className={cn(liked && "fill-destructive stroke-destructive")} />
          2.1K
        </Button>
        <Button variant="ghost" size="sm">
          <MessageCircleIcon />
          1.4K
        </Button>
        <Button variant="ghost" size="sm">
          <RepeatIcon />
          669
        </Button>
        <Button variant="ghost" size="sm">
          <SendIcon />
          1.1K
        </Button>
      </CardFooter>
    </Card>
  )
}

产品卡片

Nike Jordan Air Rev
Nike Jordan Air Rev
EU38Black and White
Crossing hardwood comfort with off-court flair. '80s-inspired construction with bold details.
Price$69.99
tsx
import { useState } from "react"
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@polyui/react/card"
import { Button } from "@polyui/react/button"
import { Badge } from "@polyui/react/badge"
import { HeartIcon } from "lucide-react"
import { cn } from "@polyui/core/lib/utils"
export function CardProduct() {
  const [liked, setLiked] = useState(false)
  return (
    <div className="relative max-w-md overflow-hidden rounded-xl bg-gradient-to-r from-neutral-600 to-violet-300 shadow-lg">
      <div className="flex h-56 items-center justify-center">
        <img
          src="https://cdn.shadcnstudio.com/ss-assets/components/card/image-11.png?width=300&format=auto"
          alt="Nike Jordan Air Rev"
          className="w-72"
        />
      </div>
      <Button
        size="icon-sm"
        onClick={() => setLiked(!liked)}
        className="absolute top-4 right-4 rounded-full bg-black/20 hover:bg-black/30"
        aria-label="Like"
      >
        <HeartIcon className={cn(liked ? "fill-destructive stroke-destructive" : "stroke-white")} />
      </Button>
      <Card className="border-none">
        <CardHeader>
          <CardTitle>Nike Jordan Air Rev</CardTitle>
          <CardDescription className="flex items-center gap-2">
            <Badge variant="outline" className="rounded-sm">
              EU38
            </Badge>
            <Badge variant="outline" className="rounded-sm">
              Black and White
            </Badge>
          </CardDescription>
        </CardHeader>
        <CardContent className="text-sm text-muted-foreground">
          Crossing hardwood comfort with off-court flair. &apos;80s-inspired construction with bold details.
        </CardContent>
        <CardFooter className="justify-between gap-3">
          <div className="flex flex-col">
            <span className="text-xs font-medium uppercase text-muted-foreground">Price</span>
            <span className="text-xl font-semibold">$69.99</span>
          </div>
          <Button size="lg">Add to cart</Button>
        </CardFooter>
      </Card>
    </div>
  )
}

用户评价

Incredible time-saver! The pre-built components are not only visually appealing but also highly customizable, fitting seamlessly into my projects.

SG
Sam Green@SamG11
tsx
import { Card, CardContent, CardFooter } from "@polyui/react/card"
import { StarIcon } from "lucide-react"
export function CardTestimonial() {
  return (
    <Card className="max-w-md border-none">
      <CardContent className="pt-4 text-sm">
        <p>
          Incredible time-saver! The pre-built components are not only{" "}
          <span className="bg-primary/10 px-0.5">visually appealing but also highly customizable</span>, fitting
          seamlessly into my projects.
        </p>
      </CardContent>
      <CardFooter className="justify-between gap-3">
        <div className="flex items-center gap-3">
          <div className="flex size-9 items-center justify-center rounded-full bg-muted text-xs font-medium ring-2 ring-ring">
            SG
          </div>
          <div className="flex flex-col gap-0.5">
            <span className="text-sm font-medium">Sam Green</span>
            <span className="text-xs text-muted-foreground">@SamG11</span>
          </div>
        </div>
        <div className="flex items-center gap-0.5">
          {[1, 2, 3, 4].map((i) => (
            <StarIcon
              key={i}
              className="size-4 fill-amber-500 stroke-amber-500 dark:fill-amber-400 dark:stroke-amber-400"
            />
          ))}
          <StarIcon className="size-4 stroke-amber-500 dark:stroke-amber-400" />
        </div>
      </CardFooter>
    </Card>
  )
}

可关闭操作

Have a project in mind?

Let's discuss! Our team is excited to hear about your projects, ideas and questions.

tsx
import { useState } from "react"
import { Card, CardHeader, CardTitle, CardContent, CardAction } from "@polyui/react/card"
import { Button } from "@polyui/react/button"
import { XIcon } from "lucide-react"
export function CardDismissibleAction() {
  const [visible, setVisible] = useState(true)
  if (!visible) {
    return (
      <Button variant="outline" size="sm" onClick={() => setVisible(true)}>
        Show card
      </Button>
    )
  }
  return (
    <Card className="relative max-w-lg shadow-none">
      <CardHeader>
        <CardTitle className="text-center">Have a project in mind?</CardTitle>
        <CardAction>
          <Button
            variant="ghost"
            size="icon-sm"
            onClick={() => setVisible(false)}
            className="rounded-full"
            aria-label="Close"
          >
            <XIcon />
          </Button>
        </CardAction>
      </CardHeader>
      <CardContent className="flex flex-col gap-4 text-center text-sm text-muted-foreground">
        <p>Let&apos;s discuss! Our team is excited to hear about your projects, ideas and questions.</p>
        <Button>Contact Our Team</Button>
      </CardContent>
    </Card>
  )
}

分组

Mystical Blue Swirl
Mystical Blue Swirl
Dive into the depths of an enchanting swirl.
Fiery Sunset Gradient
Fiery Sunset Gradient
Experience the warmth of a radiant sunset.
Cosmic Blue Waves
Cosmic Blue Waves
Explore the mysteries of the cosmos.
tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@polyui/react/card"
import { Button } from "@polyui/react/button"
export function CardGroup() {
  return (
    <div className="flex *:rounded-none *:shadow-none max-xl:flex-col max-xl:*:[&:not(:last-child)]:border-b-0 max-xl:*:first:rounded-t-xl max-xl:*:last:rounded-b-xl xl:*:[&:not(:last-child)]:border-r-0 xl:*:first:rounded-l-xl xl:*:last:rounded-r-xl">
      {groupCards.map((card) => (
        <Card key={card.title} className="overflow-hidden pt-0">
          <CardContent className="px-0">
            <img src={card.img} alt={card.title} className="aspect-video w-full object-cover" />
          </CardContent>
          <CardHeader>
            <CardTitle>{card.title}</CardTitle>
            <CardDescription>{card.desc}</CardDescription>
          </CardHeader>
          <CardFooter className="gap-3 max-sm:flex-col max-sm:items-stretch">
            <Button>Explore More</Button>
            <Button variant="outline">Download Now</Button>
          </CardFooter>
        </Card>
      ))}
    </div>
  )
}

聚光灯

Hover for the Glow-Up
Glide your cursor here and watch magic unfold — an experience designed just for you.
tsx
import { useEffect, useRef } from "react"
import { Card, CardHeader, CardTitle, CardContent } from "@polyui/react/card"
export function CardSpotlight() {
  const blobRef = useRef<HTMLDivElement>(null)
  const fakeBlobRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const handleMouseMove = (ev: MouseEvent) => {
      const blob = blobRef.current
      const fblob = fakeBlobRef.current
      if (!blob || !fblob) return
      const rec = fblob.getBoundingClientRect()
      blob.style.opacity = "1"
      blob.animate(
        [
          {
            transform: `translate(${ev.clientX - rec.left - rec.width / 2}px, ${ev.clientY - rec.top - rec.height / 2}px)`,
          },
        ],
        { duration: 300, fill: "forwards" }
      )
    }
    window.addEventListener("mousemove", handleMouseMove)
    return () => window.removeEventListener("mousemove", handleMouseMove)
  }, [])

  return (
    <div className="group bg-border relative overflow-hidden rounded-xl p-px transition-all duration-300">
      <Card className="group-hover:bg-card/90 max-w-80 border-none transition-all duration-300 group-hover:backdrop-blur-[20px]">
        <CardHeader>
          <CardTitle>Hover for the Glow-Up</CardTitle>
        </CardHeader>
        <CardContent className="text-sm text-muted-foreground">
          Glide your cursor here and watch magic unfold — an experience designed just for you.
        </CardContent>
      </Card>
      <div
        ref={blobRef}
        className="absolute top-0 left-0 size-20 rounded-full bg-sky-600/60 opacity-0 blur-2xl transition-all duration-300 dark:bg-sky-400/60"
      />
      <div ref={fakeBlobRef} className="absolute top-0 left-0 size-20 rounded-full" />
    </div>
  )
}

3D 悬停

Dynamic 3D Hover Card
3D hover card

Experience interactive depth and motion with this sleek 3D hover effect. Move your cursor to see it come alive!

vue
import { Card, CardHeader, CardTitle, CardContent } from "@polyui/vue/card"
export function Card3DHover() {
  return (
    <Card class="max-w-md">
      <CardHeader>
        <CardTitle>Dynamic 3D Hover Card</CardTitle>
      </CardHeader>
      <CardContent class="space-y-4 text-sm text-muted-foreground">
        <img
          src="https://cdn.shadcnstudio.com/ss-assets/components/card/image-10.png?width=350&format=auto"
          alt="3D hover card"
          class="aspect-video w-full rounded-md object-cover"
        />
        <p>
          Experience interactive depth and motion with this sleek 3D hover effect. Move your cursor to see it come
          alive!
        </p>
      </CardContent>
    </Card>
  )
}

属性

属性类型默认值说明
Card · classNamestring应用于卡片根元素的额外类名。
CardHeader · classNamestring应用于卡片头部区域的额外类名,默认含 padding。
CardTitle · as"h1" | "h2" | "h3" | "h4" | "h5" | "h6""h3"标题渲染的 HTML 标签,默认为 h3。
CardDescription · classNamestring应用于卡片描述文字的额外类名,默认为 muted 颜色。
CardContent · classNamestring应用于卡片内容区域的额外类名,默认含水平 padding。
CardFooter · classNamestring应用于卡片底部区域的额外类名,默认为 flex 布局。