Home > Enterprise >  How to pass JSX to textarea component as children?
How to pass JSX to textarea component as children?

Time:10-18

I have the following react text area component:

<Textarea
  autoFocus
  placeholder={(formState.commentBody && formState.commentBody !== '') ? formState.commentBody : intl.get('issue_details_placeholder_add_a_comment')}
  value={formState.commentBody}
  onChange={handleChange('commentBody')}
  ref={$textareaRef}
/>

what gets displayed in the textarea is just formState.commentBody and Textarea is defined as:

import React, { forwardRef } from 'react';
import TextareaAutoSize from 'react-textarea-autosize';
import { StyledTextarea } from './Styles';

const Textarea = forwardRef(({ className, invalid, onChange, ...textareaProps }, ref) => (
  <StyledTextarea className={className} invalid={invalid}>
    <TextareaAutoSize
      {...textareaProps}
      onChange={event => onChange(event.target.value, event)}
      ref={ref || undefined}
    />
  </StyledTextarea>
));

export default Textarea;

Now, instead of passing a string (formState.commentBody) as value into Textarea, I want to pass some jsx code:

<blockquote>
    this is a customizable text and clickable within textarea 
</blockquote>

into <textarea> as its children, such that it would be equivalent to :

<textarea>
    <blockquote>
        this is a customizable text and clickable within textarea 
    </blockquote>
</textarea>

The final goal is to be able to display block code inside the TextareaAutoSize.

How can I achieve this?

I tried to code inside the TextareaAutoSize component directly like this:


const Textarea = forwardRef(({ className, invalid, onChange, ...textareaProps }, ref) => (
  <StyledTextarea className={className} invalid={invalid}>
    <TextareaAutoSize
      {...textareaProps}
      onChange={event => onChange(event.target.value, event)}
      ref={ref || undefined}
    >

      <blockquote>
        hahaha
      </blockquote>

    </TextareaAutoSize>
  </StyledTextarea>
));

export default Textarea;

However it is displaying:

enter image description here

Why is this happening?

CodePudding user response:

You can't embed html content in a textarea (docs). To do this, you could consider using a content-editable div:

<div contenteditable="true">
 <blockquote>hahaha</blockquote>
</div>

CodePudding user response:

Now, instead of passing a string (formState.commentBody) as value into Textarea, I want to pass some jsx code.

The value of a text area is a string (text), not markup (spec). Although you could use JSX to create content for it, you'd have to render those elements to a string in order to make them the value of a textarea (via ReactDOMServer.renderToString or similar), like this:

const { useState } = React;

const Textarea = ({children, value, updateValue}) => {
    if (typeof value === "undefined") {
        value = ReactDOMServer.renderToString(children);
    }
    return (
        <textarea value={value} onChange={() => {/*...*/}} />
    );
};

const Example = () => {
    return (
        <Textarea>
            <blockquote>
                this is a customizable text and clickable within textarea
            </blockquote>
        </Textarea>
    );
};

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Example />);
textarea {
    width: 100%;
    height: 4em;
}
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom-server-legacy.browser.development.js"></script>

But there's no point in doing that vs. just creating a string in the first place, and it's not updateable. (I couldn't tell from the question whether you wanted to be able to update it...but it's a textarea, so...) You'd have to pull apart the bits of it in order to then use those bits when recreating the element. A string would be updateable, so I'd suggest just using a string:

const { useState } = React;

const Textarea = ({value, updateValue}) => {
    const onChange = ({currentTarget: {value}}) => {
        updateValue(value);
    };
    return (
        <textarea value={value} onChange={onChange} />
    );
};

const initialCommentBody = `<blockquote>
    this is a customizable text and clickable within textarea
</blockquote>`;
const Example = () => {
    const [ commentBody, setCommentBody ] = useState(initialCommentBody);
    return (
        <Textarea value={commentBody} updateValue={setCommentBody} />
    );
};

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Example />);
textarea {
    width: 100%;
    height: 4em;
}
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>

  • Related