In this article, I'll be explaining how to create a custom paragraph component which will take a prop as well other valid HTML properties valid for a paragraph.
Let's say you were to write a custom paragraph component in React which would be called <ParaText />
. You want to pass some string value as a property called text
which would then be passed on to the p
element like this:
<p>{text}</p>
How would you go about writing this component? You may think about listing all valid properties for a paragraph element and then passing it on, but it soon becomes clear that this approach is unrealistic:
const ParaText = ({ text, id, class, style, title}) => <p>{text}</p>;
Here we've added just 4 attributes (and the text
prop) that would need to be passed on. If we were to include all necessary attributes we would need 10 props and that's not a good approach. We could instead use the spread syntax to collect the remaining props in an object that we will call rest
for this tutorial.
const ParaText = ({ text, ...rest}) => <p {...rest}>{text}</p>;
So far it's all been JavaScript but now we'll use an interface to define the type of the properties object so that only valid properties are passed to the ParaText component. We'll call the interface ParaTextType
.
interface ParaTextType {
text: string;
id?: string;
class?: string;
style?: string;
title?: string;
}
const ParaText = ({ text, ...rest}: ParaTextType) =>
<p {...rest}>{text}</p>;
But our ParaTexType
definition for what a paragraph should accept isn't as precise as the built-in ones in React. And we only want to include the text
property in our custom component and intrinsically inherit the normal attributes of the native paragraph element. There are a number of ways to achieve this but for this tutorial, we'll take a look at three:
1. ComponentPropsWithoutRef
This interface is available on the React namespace and it provides the appropriate props for a given component type without any ref that the component accepts. So that means if you passed a paragraph to ComponentPropsWithoutRef
like this:
React.ComponentPropsWithoutRef<"p">
You should get the valid props (attributes) for the paragraph element, which ParaTextType
can extend. For brevity's sake, let's import ComponentPropsWithoutRef
from React:
import { ComponentPropsWithoutRef } from 'react';
interface ParaTextType extends ComponentPropsWithoutRef<"p"> {
text: string;
}
const ParaText = ({ text, ...rest}: ParaTextType) => <p {...rest}>{text}</p>;
Then you can simply use the component this way:
<ParaText text="John" />
Another interface similar to ComponentPropsWithoutRef
is ComponentProps
. The latter provides a ref
property which can be used in the paragraph element.
2. JSX.IntrinsicElements
The namespace JSX
is available globally from which we can extract the type we want by indexingJSX.IntrinsicElements
with the HTML node name:
JSX.IntrinsicElements['p']
But we can't use extends
with square brackets: this seems to be a TypeScript limitation. So we cannot do:
interface ParaTexType extends JSX.IntrinsicElements['p']
We would have to hold it in a separate type variable. Let's call this variable ParaTexTypeFromJSX
, which we would then use like this:
type ParaTexTypeFromJSX = JSX.IntrinsicElements['p'];
interface ParaTexType extends ParaTexTypeFromJSX {
label: string;
}
const ParaText = ({ text, ...rest}: ParaTextType) => <p {...rest}>{text}</p>;
3. HTMLParagraphElement
You can also define the return value of ParaText1
which in the end is a functional component that renders a paragraph. So we get the properties (HTML attributes) for a paragraph and use the intersection literal (&
) to include our text
prop.
const ParaText1: React.FunctionComponent<
React.HTMLAttributes<HTMLParagraphElement> & {
text: string;
}
> = ({ text, ...rest }: { text: string }) => <p {...rest}>{text}</p>;
Then you can then use the component as follows:
<ParaText text="John" />
And you should get a paragraph element displaying "John". You could extend this component as you wish, like limiting the text length and using an ellipsis (...) afterwards.
Conclusion
We looked at how we can create or mirror a paragraph element in React using the built-in types. There are other interfaces, like InputHTMLAttributes
, HTMLAttributes
and HTMLProps
that might as well get the job done or be a bad choice but for this tutorial, we'll keep it at 3.
Top comments (0)