React component is not accepting JSX Element as prop

1.7k Views Asked by At

I would render a component as a Label content instead of a string.

Actually I'm getting this error:

The shorthand prop for "Box" component was passed a JSX element but this slot only supports string|number|object|array|ReactElements.

import AudioItem from '../containers/Media'
const AudioLabel = (props) => {
    let url = "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3"
    const [audio] = useState(new Audio(url));
    const [isPaused, setIsPaused] = useState(audio.paused)
    return (<Label content={({ ...props }) => (<><span>{props.content}</span> <AudioItem isPaused={isPaused} setIsPaused={setIsPaused} audio={audio} /></>)}
        circular
        image={{
            src: 'public/images/avatar/small/matt.jpg',
            avatar: true,
        }}
        icon={
            <CloseIcon
            />}
    />)
}
export default AudioLabel

Called component as prop.

import { Button, Header, List, RadioGroup, ItemLayout } from '@fluentui/react-northstar'
import { PlayIcon, PauseThickIcon } from '@fluentui/react-icons-northstar'

const AudioItem = (props) => {
    return (
        <ItemLayout
            headerMedia={<Button icon={props.isPaused ? (<PlayIcon />) : (<PauseThickIcon />)} onClick={() => { props.isPaused ? props.audio.play() : props.audio.pause(); props.setIsPaused(props.audio.paused) }} text content={props.isPaused ? "Play" : "Pause"} />}
        />
    )
}

How can I pass a component (with props) as content?

Issue reproduction

3

There are 3 best solutions below

1
On BEST ANSWER

I've checked the documentation of fluent. What you are trying to achieve is called render props in react. But fluent library named this as Shorthand Props

According to their doc you need to follow a specific pattern to achieve this. Here i've added the code for the Label Component and it removes the error. sandbox_link

<Label
      content={{
        chidren: ({ ...props }) => (
        <>
          <span>{props.content}</span>
            <AudioItem
              isPaused={isPaused}
              setIsPaused={setIsPaused}
              audio={audio}
            />
        </>)
      }}
      circular 
      image={{
        src: "public/images/avatar/small/matt.jpg",
        avatar: true
      }}
      icon={<CloseIcon />}
    />

2
On

An arbitrary function is not a functional component. If you want React to compile a function as a component, you need (a) an identifier in scope and (b) a capital letter as first letter of this identifier. doc.

To make your code work, you need to create a new component that will render your span and your AudioItem.

Working example here: code

0
On

I'd say that it's not the best idea to pass JSX as props, but if you're certain that's what you want, you can always convert it to string, then pass it, then convert it back again; like so (simple example):

const JSXToPass = () => {
    return (
        <div> example </div>
    );
}

const Parent = () => {
    return (
        <Child content={React.renderToString(JSXToPass)} />
    );
}

const Child = (props) => {
    return (
        <div dangerouslySetInnerHTML={{__html: props.content}} />
    );
}