Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions apps/examples/calcom/app/(dashboard)/booking/bookings-list.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { Badge } from "@coss/ui/components/badge";
import { Button } from "@coss/ui/components/button";
import { Button, buttonVariants } from "@coss/ui/components/button";
import {
Card,
CardFrame,
Expand Down Expand Up @@ -400,16 +400,19 @@ function BookingListItem({
/>
</div>
{showJoinLink && (
<Button
className="pointer-events-auto min-w-0 max-w-full whitespace-normal"
render={<Link href="#join" />}
size="xs"
<Link
className={buttonVariants({
className:
"pointer-events-auto min-w-0 max-w-full whitespace-normal",
size: "xs",
variant: "outline",
})}
href="#join"
title={locationLabel}
variant="outline"
>
<VideoIcon />
<span className="truncate">{locationLabel}</span>
</Button>
</Link>
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { Badge } from "@coss/ui/components/badge";
import { Button } from "@coss/ui/components/button";
import { Button, buttonVariants } from "@coss/ui/components/button";
import {
Card,
CardFrame,
Expand Down Expand Up @@ -201,15 +201,17 @@ export function BookingsList() {
</p>
</div>
{locationLabel && (
<Button
className="pointer-events-auto"
render={<Link href="#join" />}
size="xs"
variant="outline"
<Link
className={buttonVariants({
className: "pointer-events-auto",
size: "xs",
variant: "outline",
})}
href="#join"
>
<VideoIcon />
{locationLabel}
</Button>
</Link>
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button } from "@coss/ui/components/button";
import { Button, buttonVariants } from "@coss/ui/components/button";
import {
Card,
CardFrame,
Expand Down Expand Up @@ -36,12 +36,12 @@ export default function NewWebhookPage() {
</CardPanel>
</Card>
<CardFrameFooter className="flex justify-end gap-2">
<Button
render={<Link href="/settings/developer/webhooks" />}
variant="outline"
<Link
className={buttonVariants({ variant: "outline" })}
href="/settings/developer/webhooks"
>
Cancel
</Button>
</Link>
<Button>Save</Button>
</CardFrameFooter>
</CardFrame>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button } from "@coss/ui/components/button";
import { Button, buttonVariants } from "@coss/ui/components/button";
import {
Card,
CardFrame,
Expand All @@ -25,14 +25,13 @@ export default async function EditAttributePage({
<>
<AppHeader>
<div className="flex min-w-0 items-start gap-3">
<Button
<Link
aria-label="Go back"
render={<Link href="/settings/organizations/attributes" />}
size="icon-sm"
variant="ghost"
className={buttonVariants({ size: "icon-sm", variant: "ghost" })}
href="/settings/organizations/attributes"
>
<ArrowLeftIcon aria-hidden="true" />
</Button>
</Link>
<AppHeaderContent title="Edit attribute">
<AppHeaderDescription>
Update a custom attribute for your team members.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
AlertDialogPopup,
AlertDialogTitle,
} from "@coss/ui/components/alert-dialog";
import { Button } from "@coss/ui/components/button";
import { Button, buttonVariants } from "@coss/ui/components/button";
import {
Card,
CardFrame,
Expand Down Expand Up @@ -127,12 +127,13 @@ export function AttributesSection({
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button
render={<Link href="/settings/organizations/attributes/new" />}
<Link
className={buttonVariants()}
href="/settings/organizations/attributes/new"
>
<PlusIcon aria-hidden="true" />
New attribute
</Button>
</Link>
</EmptyContent>
</Empty>
);
Expand All @@ -144,14 +145,13 @@ export function AttributesSection({
<CardFrameHeader>
<CardFrameTitle>Custom</CardFrameTitle>
<CardFrameAction>
<Button
render={<Link href="/settings/organizations/attributes/new" />}
type="button"
variant="outline"
<Link
className={buttonVariants({ variant: "outline" })}
href="/settings/organizations/attributes/new"
>
<PlusIcon aria-hidden="true" />
Add
</Button>
</Link>
</CardFrameAction>
</CardFrameHeader>
<Card className="rounded-b-none!">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button } from "@coss/ui/components/button";
import { Button, buttonVariants } from "@coss/ui/components/button";
import {
Card,
CardFrame,
Expand All @@ -19,14 +19,13 @@ export default function NewAttributePage() {
<>
<AppHeader>
<div className="flex min-w-0 items-start gap-3">
<Button
<Link
aria-label="Go back"
render={<Link href="/settings/organizations/attributes" />}
size="icon-sm"
variant="ghost"
className={buttonVariants({ size: "icon-sm", variant: "ghost" })}
href="/settings/organizations/attributes"
>
<ArrowLeftIcon aria-hidden="true" />
</Button>
</Link>
<AppHeaderContent title="New attribute">
<AppHeaderDescription>
Create a custom attribute for your team members.
Expand Down
14 changes: 8 additions & 6 deletions apps/examples/calcom/components/app/app-command.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { useAutocompleteFilter } from "@coss/ui/components/autocomplete";
import { Button } from "@coss/ui/components/button";
import { Button, buttonVariants } from "@coss/ui/components/button";
import {
Command,
CommandCollection,
Expand Down Expand Up @@ -696,14 +696,16 @@ export function AppCommand(): React.ReactElement {
{aiState.referenceLinks.length > 0 && (
<div className="mt-8 flex flex-wrap gap-2">
{aiState.referenceLinks.map((link, index) => (
<Button
<Link
className={buttonVariants({
size: "sm",
variant: "secondary",
})}
href={link.url}
key={`${link.url}-${index}`}
render={<Link href={link.url} />}
size="sm"
variant="secondary"
>
{link.title}
</Button>
</Link>
))}
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button } from "@coss/ui/components/button";
import { buttonVariants } from "@coss/ui/components/button";
import { ArrowLeftIcon } from "lucide-react";
import Link from "next/link";
import type * as React from "react";
Expand All @@ -8,14 +8,14 @@ import { SettingsDrawer } from "@/components/settings/settings-drawer";
export function SettingsMobileHeader(): React.ReactElement {
return (
<MobileHeader>
<Button
<Link
aria-label="Back"
render={<Link href="/event-types" />}
variant="ghost"
className={buttonVariants({ variant: "ghost" })}
href="/event-types"
>
<ArrowLeftIcon className="-ms-0.5" />
<span>Back</span>
</Button>
</Link>
<SettingsDrawer />
</MobileHeader>
);
Expand Down
25 changes: 22 additions & 3 deletions apps/ui/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -811,15 +811,16 @@ When creating a particle equivalent to an origin component:
- Understand why certain classes were used in origin
4. **Look at existing particles** in the same category for consistency
5. **Understand the differences:**
- `asChild` → `render` prop
- `asChild` → `render` prop (triggers / composed parts — not Button-as-link)
- Button links → `buttonVariants` on `<a>` / `Link` (not `Button render`)
- `*Content` → `*Popup` or `*Panel`
- `onSelect` → `onClick` (Menu)
- `type="multiple"` → `multiple={true}`
- Size differences (coss is more compact)

### Key Migration Patterns

**asChild → render:**
**asChild → render (triggers / composed parts):**

```tsx
// Origin (Radix)
Expand All @@ -831,6 +832,23 @@ When creating a particle equivalent to an origin component:
<MenuTrigger render={<Button />}>Open</MenuTrigger>
```

**Button links → `buttonVariants` (not `Button render`):**

```tsx
// Origin (Radix / older coss)
<Button asChild>
<Link href="/login">Login</Link>
</Button>
// or: <Button render={<Link href="/login" />}>Login</Button>

// coss (Base UI Button)
import { buttonVariants } from "@/registry/default/ui/button";

<Link className={buttonVariants()} href="/login">
Login
</Link>
```

**Component naming:**

```tsx
Expand Down Expand Up @@ -1019,7 +1037,8 @@ const handleSubmit = async () => {

- Avoid Next.js-specific APIs (`next/link`, `next/image`) unless the particle specifically demonstrates Next.js integration
- Use standard HTML elements and React patterns
- For navigation, use standard `<a>` tags or demonstrate with `render` prop
- For navigation that should look like a button, style `<a>` / `Link` with `buttonVariants` — do not use `<Button render={<a|Link />}>`
- Other primitives may still use `render` for links (for example `BreadcrumbLink`, `Badge`, `MenuLinkItem`)

---

Expand Down
34 changes: 16 additions & 18 deletions apps/ui/app/docs/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { LinkSquare02Icon } from "@hugeicons/core-free-icons";
import { HugeiconsIcon } from "@hugeicons/react";
import Link from "next/link";
import { notFound } from "next/navigation";
import { Button } from "@/registry/default/ui/button";
import { buttonVariants } from "@/registry/default/ui/button";
import { Card, CardFrame, CardPanel } from "@/registry/default/ui/card";
import { ScrollArea } from "@/registry/default/ui/scroll-area";
import { DocsCopyPage } from "@/components/docs-copy-page";
Expand Down Expand Up @@ -77,23 +77,21 @@ export default async function Page(props: {
</div>
<div className="flex items-center space-x-2 pt-4">
{links?.doc && (
<Button
render={
<Link
href={links.doc}
rel="noreferrer"
target="_blank"
>
<HugeiconsIcon
icon={LinkSquare02Icon}
strokeWidth={2.5}
/>
API Reference
</Link>
}
size="xs"
variant="outline"
/>
<Link
className={buttonVariants({
size: "xs",
variant: "outline",
})}
href={links.doc}
rel="noreferrer"
target="_blank"
>
<HugeiconsIcon
icon={LinkSquare02Icon}
strokeWidth={2.5}
/>
API Reference
</Link>
)}
<DocsCopyPage page={rawContent} />
</div>
Expand Down
22 changes: 8 additions & 14 deletions apps/ui/app/not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import { RiArrowLeftLine } from "@remixicon/react";
import type { Metadata } from "next";
import Link from "next/link";
import { Button } from "@/registry/default/ui/button";
import { buttonVariants } from "@/registry/default/ui/button";

export const metadata: Metadata = {
description:
Expand All @@ -24,19 +24,13 @@ export default function NotFound() {
moved.
</PageHeaderDescription>
<div className="mt-4">
<Button
className="group"
render={
<Link href="/">
<RiArrowLeftLine
aria-hidden="true"
className="-ms-1 opacity-60 transition-transform group-hover:-translate-x-0.5"
/>
Back to Home
</Link>
}
size="lg"
/>
<Link className={buttonVariants({ className: "group" })} href="/">
<RiArrowLeftLine
aria-hidden="true"
className="-ms-1 opacity-60 transition-transform group-hover:-translate-x-0.5"
/>
Back to Home
</Link>
</div>
</PageHeader>
</div>
Expand Down
Loading
Loading