Reuse, Share & Extend
The extend function allows extending upon almost any react-component with our classmate syntax.
We pass a input component and extend it with our classmate syntax. The extend function returns a new component.
// this could be almost any component that accepts a className prop
const MyInput = ({ ...props }: InputHTMLAttributes<HTMLInputElement>) => <input {...props} />
const StyledInput = rc.extend(MyInput)<{ $trigger?: boolean }>`
bg-white
border-1
${(p) => (p.$trigger ? "border-error" : "border-gray")}
`
Extend as often as you wish:
const ExtendedStyledInput = rc.extend(StyledInput)<{ $someBool?: boolean }>`
custom-class
${(p) => (p.$someBool ? "shadow" : "")}
${(p) => (p.type === "text" ? "text-lg" : "")}
${(p) => (p.$trigger ? "text-red" : "")}
`
Base
documentation page<StyledInput type="text" $trigger />
// renders:
// <input type="text" class="bg-white border-1 border-error" />
<ExtendedInput type="text" $trigger $someBool />
// renders:
// <input type="text" class="bg-white border-1 border-error custom-class shadow text-lg text-red" />
rc.extend
?There are two different scenarios where extending components is helpful:
When you wanna extend a "base"-component, in which you desired to set less specific styling classnames (e.g. outer margins, typography, etc.) rc.extend
could be your pick. For example these are some elements which are re-used all over this documentation:
// ...
import Notebox from "#components/common/Notebox"
export const Section = rc.extend(Notebox)`
mb-8
`
export const SectionHeadline = rc.extend(H3Headline)`
mb-4
`
export const SectionInnerHeadline = rc.extend(H4Headline)`
mt-4
`
// ....
import { ArrowBigDown } from "lucide-react"
import rc from "react-classmate"
const StyledLucideArrow = rc.extend(ArrowBigDown)`
md:-right-4.5
right-1
slide-in-r-20
`
// ts: we can pass only props which are accessible on a `lucid-react` Component
export default () => <StyledLucideArrow stroke="3" />
A classic example where you find yourself extending the same component multiple times to assign almost similar classnames:
// probably unused :/
const GradientBase = rc.div`
absolute -mt-100 left-0 w-full
h-100
bg-gradient-to-t
pointer-events-none
`
const VariantsGradient = rc.extend(GradientBase)`
from-primarySuperLight
top-0
`
const ThanksGradient = rc.extend(GradientBase)`
from-primaryLight/40
bottom-0
`
const FooterGradient = rc.extend(GradientBase)`
from-light
bottom-0
`
In the example above it's very likely that we will not implement the GradientBase
in the jsx later and might want to consider creating a variant out of our blueprint from above. Here is an example how we could do it:
type GradientType = "variants" | "thanks" | "footer"
const SectionGradient = rc.div.variants<{ $type: GradientType }>({
base: `
absolute -mt-100 left-0 w-full
h-100
bg-gradient-to-t
pointer-events-none
`,
variants: {
$type: {
variants: "from-primarySuperLight top-0",
thanks: "from-primaryLight/40 bottom-0",
footer: "from-light",
}
}
})