Skip to content

Commit

Permalink
docs: polymorphism
Browse files Browse the repository at this point in the history
  • Loading branch information
joe-bell committed Jul 21, 2023
1 parent 6e12730 commit be0dcfa
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 18 deletions.
18 changes: 1 addition & 17 deletions docs/pages/docs/faqs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,7 @@ Long story short: it's unnecessary.
- Polymorphism is free; just apply the class to your preferred HTML element
- Less opinionated; you're free to build components with `cva` however you'd like

<details>

{" "}

<summary>Example: Polymorphic Components</summary>

There's no `as` prop in `cva`, because HTML is free:

```diff
-- // A familiar `styled` button as a link
-- <Button as="a" href="#" variant="primary">Button as a link</Button>

++ // A `cva` button as a link
++ <a href="#" class={button({variant: "primary"})}>Button as a link</a>
```

</details>
See the ["Polymorphism"](/docs/getting-started/polymorphism) documentation for further recommendations.

## How Can I Create [Responsive Variants like Stitches.js](https://stitches.dev/docs/responsive-styles#responsive-variants)?

Expand Down
3 changes: 2 additions & 1 deletion docs/pages/docs/getting-started/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"compound-components": "",
"typescript": "TypeScript",
"extending-components": "",
"mixing-components": ""
"mixing-components": "",
"polymorphism": ""
}
81 changes: 81 additions & 0 deletions docs/pages/docs/getting-started/polymorphism.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Polymorphism

`cva` components are polymorphic (and framework-agnostic) by default; just apply the class to your preferred HTML element…

```tsx
import { button } from "./components/button";

export default () => (
<a className={button()} href="/sign-up">
Sign up
</a>
);
```

## Alternative Approaches

### React

If you'd prefer to use a React-based API, `cva` strongly recommends using [`@radix-ui`'s `Slot` component](https://www.radix-ui.com/docs/primitives/utilities/slot) to create your own `asChild` prop.

```tsx
// ./components/button.tsx
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";

const button = cva("button", {
variants: {
intent: {
primary: [
"bg-blue-500 text-white",
"text-white",
"border-transparent",
"hover:bg-blue-600",
],
secondary: [
"bg-white",
"text-gray-800",
"border-gray-400",
"hover:bg-gray-100",
],
},
},
defaultVariants: {
intent: "primary",
},
});

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof button> {
asChild?: boolean;
}

export const Button: React.FC<ButtonProps> = ({
asChild,
className,
intent,
...props
}) => {
const Comp = asChild ? Slot : "button";

return <Comp className={button({ intent, className })} {...props} />;
};
```

#### Usage

```tsx
import { Button } from "./components/button";

// Renders:
// <a href="/sign-up" class="bg-blue-500 text-white text-white border-transparent hover:bg-blue-600">
// Sign up
// </a>
export default () => (
<Button asChild>
<a href="/sign-up">Sign up</a>
</Button>
);
```

0 comments on commit be0dcfa

Please sign in to comment.