Next.js Discord

Discord Forum

take component as input in another component

Unanswered
shadow posted this in #help-forum
Open in Discord
can i do something like this?

interface TooltipIconProps{
  icon: React.ComponentType<any>;
  text: string;
}


export function TooltipIcon({ icon: IconComponent, text }: TooltipIconProps) {
  return (
    <div className="group relative w-max">
      <IconComponent className="text-blue-600" />
      <span className="pointer-events-none absolute right-7 -top-3 w-max opacity-0 transition-opacity group-hover:opacity-100 bg-slate-600 p-2 py-1 rounded-md font-semibold">
        {text}
      </span>
    </div>
  );
}


import { BiCategoryAlt } from "react-icons/bi";

<Tooltip icon={<BiCategoryAlt/>} text="test"/>

30 Replies

Giant panda
My preference is icon={<BiCategoryAlt/>} and typing icon as ReactNode
yeah but here they use <IconComponent className="text-blue-600" /> so your approach doesn't work so easily
i use both, what to choose depends on the scenario
Giant panda
Oh I didn't notice the usage - I'd wager it's not necessarily inteded to begin with.
i actually have an <Icon /> component where i add some default styling and variants so i can use something like <Icon icon={ArrowUp} variant="large" />
like buttons
@Giant panda My preference is `icon={<BiCategoryAlt/>}` and typing `icon` as `ReactNode`
interface TooltipIconProps{
  icon: ReactNode;
  text: string;
}


like this?
@shadow js interface TooltipIconProps{ icon: ReactNode; text: string; } like this?
<IconComponent className="text-blue-600" /> will no longer be possible if you pass a node. Good if it is what you want.
@rphlmr 🫡 `<IconComponent className="text-blue-600" />` will no longer be possible if you pass a node. Good if it is what you want.
interface TooltipIconProps{
 icon: ReactNode;
  text: string;
}


export function TooltipIcon({ icon: IconComponent, text }: TooltipIconProps) {
  return (
    <div className="group relative w-max">
      {cloneElement(icon, {
                      className: `text-blue-600 ${icon.props.className}`, 
                  })}
      <span className="pointer-events-none absolute right-7 -top-3 w-max opacity-0 transition-opacity group-hover:opacity-100 bg-slate-600 p-2 py-1 rounded-md font-semibold">
        {text}
      </span>
    </div>
  );
}


Merging styles requires an other lib like tailwind-merge if you don't want style merging issues
@shadow so needs to be `React.ComponentType<any>`?
It depends your preference
what Near propose allows you to override default classnames of your component passed by props
example from your code: icon is default to text blue. At some point you can change the color:

<Tooltip icon={<BiCategoryAlt/>} text="test"/> //blue
<Tooltip icon={<BiCategoryAlt className="text-red-600" />} text="test"/> //red
@shadow what is `cloneElement`?
It comes from React. It is to clone an element and manipulate its props
ah yes lol
it's IconComponent
you can remove the props rename if you want
'IconComponent' is possibly 'null' or 'undefined'
by convention :
icon => a node
Icon => an Component
@shadow `'IconComponent' is possibly 'null' or 'undefined'`
{icon ? cloneElement(icon, {
                      className: `text-blue-600 ${icon.props.className}`, 
                  }) : null}
make a ternary, but I don't know why it thinks it could be null
ah it's the wrong type
node can be nullish (undefined/null)
interface TooltipIconProps{
 icon: React.ReactElement<{ className?: string }>;
  text: string;
}


is a better type
okay no errors, let me test it
its working thanks!!