Components
Product Card
A product tile with image, name, and price. Purely presentational — no Morphos equivalent.
Installation
npx kosmesis add product-cardpnpm dlx kosmesis add product-cardyarn dlx kosmesis add product-cardbunx kosmesis add product-cardCopy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { cn } from "@/lib/utils";export interface ProductCardProps { image: string; name: string; price: string; originalPrice?: string; class?: string; children?: Children;}@Component()export class ProductCard extends StatelessComponent<ProductCardProps> { render() { const { image, name, price, originalPrice, class: cls, children } = this.props; return ( <div data-slot="product-card" class={cn("flex flex-col gap-3 rounded-xl border bg-card p-3 text-card-foreground", cls)}> <div class="aspect-square overflow-hidden rounded-lg bg-muted"> <img src={image} alt={name} class="size-full object-cover" /> </div> <div class="flex flex-col gap-1 px-1"> <p class="truncate text-sm font-medium">{name}</p> <div class="flex items-baseline gap-2"> <span class="text-sm font-semibold">{price}</span> {originalPrice && <span class="text-xs text-muted-foreground line-through">{originalPrice}</span>} </div> </div> {children} </div> ); }}Install the following dependencies:
npm install @praxisjs/csspnpm add @praxisjs/cssyarn add @praxisjs/cssbun add @praxisjs/cssCopy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class ProductCardStyles extends Stylesheet { $root = this.css({ display: "flex", flexDirection: "column", gap: "0.75rem", borderRadius: "0.75rem", border: `1px solid ${t.border}`, backgroundColor: t.card, color: t.cardForeground, padding: "0.75rem", }); $image = this.css({ aspectRatio: "1 / 1", overflow: "hidden", borderRadius: "0.5rem", backgroundColor: t.muted }); $img = this.css({ width: "100%", height: "100%", objectFit: "cover" }); $body = this.css({ display: "flex", flexDirection: "column", gap: "0.25rem", padding: "0 0.25rem" }); $name = this.css({ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontSize: "0.875rem", fontWeight: 500 }); $priceRow = this.css({ display: "flex", alignItems: "baseline", gap: "0.5rem" }); $price = this.css({ fontSize: "0.875rem", fontWeight: 600 }); $originalPrice = this.css({ fontSize: "0.75rem", color: t.mutedForeground, textDecoration: "line-through" });}export interface ProductCardProps { image: string; name: string; price: string; originalPrice?: string; class?: string; children?: Children;}@Component()export class ProductCard extends StatelessComponent<ProductCardProps> { @Styled(ProductCardStyles) $s!: ProductCardStyles; render() { const { image, name, price, originalPrice, class: cls, children } = this.props; return ( <div data-slot="product-card" class={cx(this.$s.$root, cls)}> <div class={this.$s.$image}> <img src={image} alt={name} class={this.$s.$img} /> </div> <div class={this.$s.$body}> <p class={this.$s.$name}>{name}</p> <div class={this.$s.$priceRow}> <span class={this.$s.$price}>{price}</span> {originalPrice && <span class={this.$s.$originalPrice}>{originalPrice}</span>} </div> </div> {children} </div> ); }}Examples
About
Purely presentational — no Morphos equivalent. children render below the price — typically an
add-to-cart Button, a Rating, or an icon-only Toggle used as a wishlist button.
Usage
import { ProductCard } from "@/components/ui/product-card";
<ProductCard image="/headphones.jpg" name="Wireless headphones" price="$89.00" originalPrice="$120.00">
<Button size="sm">Add to cart</Button>
</ProductCard>Props
| Prop | Type | Default |
|---|---|---|
image | string | — |
name | string | — |
price | string | — |
originalPrice | string | — |
class | string | — |