S
SolidJS•12mo ago
-=Camille=-

Component that can render a different tag depending on prop?

I want to make a title that renders a different component depending on the as props you give it. I've written the following component, using a Switch to render the correct component. I am not sure if this is the best way to accomplish what I want. What are your opinions on the way I should have done this? Is this good practice, or is there a cleaner way? Thank you very much for your help and your time! šŸ™
import { JSXElement, Match, Switch } from 'solid-js';

import { TextColour } from './types/TextColour';

type TitleProps = {
/**
* The heading level of the title. Defaults to 'h1'.
*/
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
colour?: TextColour;
children: JSXElement;
variant?: 's' | 'm' | 'l' | 'xl';
};

/**
* Renders a title component based on the specified heading level.
* Defaults to 'h1' heading level, 'black' colour, and 'm' variant size.
*
* @example
* <Title as="h2" colour="dark-brown" variant="l">My Title</Title>
*/
const Title = (props: TitleProps) => {
const getClasslist = () => {
const classes: Record<string, boolean> = {};
classes[`title--${props.variant ?? 'm'}`] = true;
classes[`title--${props.colour ?? TextColour.BLACK}`] = true;
return classes;
};

return (
<Switch fallback={<h1 classList={getClasslist()}>{props.children}</h1>}>
<Match when={props.as === 'h2'}>
<h2 classList={getClasslist()}>{props.children}</h2>
</Match>
<Match when={props.as === 'h3'}>
<h3 classList={getClasslist()}>{props.children}</h3>
</Match>
<Match when={props.as === 'h4'}>
<h4 classList={getClasslist()}>{props.children}</h4>
</Match>
<Match when={props.as === 'h5'}>
<h5 classList={getClasslist()}>{props.children}</h5>
</Match>
<Match when={props.as === 'h6'}>
<h6 classList={getClasslist()}>{props.children}</h6>
</Match>
</Switch>
);
};

export default Title;
import { JSXElement, Match, Switch } from 'solid-js';

import { TextColour } from './types/TextColour';

type TitleProps = {
/**
* The heading level of the title. Defaults to 'h1'.
*/
as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
colour?: TextColour;
children: JSXElement;
variant?: 's' | 'm' | 'l' | 'xl';
};

/**
* Renders a title component based on the specified heading level.
* Defaults to 'h1' heading level, 'black' colour, and 'm' variant size.
*
* @example
* <Title as="h2" colour="dark-brown" variant="l">My Title</Title>
*/
const Title = (props: TitleProps) => {
const getClasslist = () => {
const classes: Record<string, boolean> = {};
classes[`title--${props.variant ?? 'm'}`] = true;
classes[`title--${props.colour ?? TextColour.BLACK}`] = true;
return classes;
};

return (
<Switch fallback={<h1 classList={getClasslist()}>{props.children}</h1>}>
<Match when={props.as === 'h2'}>
<h2 classList={getClasslist()}>{props.children}</h2>
</Match>
<Match when={props.as === 'h3'}>
<h3 classList={getClasslist()}>{props.children}</h3>
</Match>
<Match when={props.as === 'h4'}>
<h4 classList={getClasslist()}>{props.children}</h4>
</Match>
<Match when={props.as === 'h5'}>
<h5 classList={getClasslist()}>{props.children}</h5>
</Match>
<Match when={props.as === 'h6'}>
<h6 classList={getClasslist()}>{props.children}</h6>
</Match>
</Switch>
);
};

export default Title;
10 Replies
-=Camille=-
-=Camille=-OP•12mo ago
I could also use a Dynamic component like this, but I don't know which is the best solution. šŸ¤”
return (
<Dynamic component={props.as ?? 'h1'} classList={getClasslist()}>
{props.children}
</Dynamic>
);
return (
<Dynamic component={props.as ?? 'h1'} classList={getClasslist()}>
{props.children}
</Dynamic>
);
Jasmin
Jasmin•12mo ago
This is the way
-=Camille=-
-=Camille=-OP•12mo ago
Is this because it's cleaner and Switch and Dynamic have the same impact? I'm just wondering if the Dynamic component has a bigger impact. The reason is that this Title will be used everywhere in my website, and I would rather not impact the performance too much. šŸ˜“ This title is not really dynamic, I just want to render a different heading level once and then leave it like this šŸ˜„
Alex Lohr
Alex Lohr•12mo ago
Dynamic certainly has the higher impact, but Solid's performance is so good that you'll hardly notice even with 1000 headlines.
-=Camille=-
-=Camille=-OP•12mo ago
Okay thanks. I'm just wondering if using a Dynamic component to just return a different header depending on the prop is a bad idea, since I actually don't need dynamism. Should I just use the prop outside a reactive context to improve the performance? I guess I would lose reactivity, but gain performance by removing the reactivity checks. I know I would not notice any significant difference, but I would like my code and websites to have the least performance impact as possible. I'm striving for eco-friendliness. šŸ˜„
bigmistqke
bigmistqke•12mo ago
i think Dynamic is a good idea. having non-reactive props is introducing mental overhead and possible bugs. if ur solo dev it might be fine for now, but then still I wouldn't start introducing non-reactive props, thinking about maintaining the code later down the line. The ecological fingerprint of Dynamic will be very tiny, especially if it doesn't upload often. I would consider it a micro-optimisation.
-=Camille=-
-=Camille=-OP•12mo ago
Okay, thanks for the feedback! You are right, I also thought that I would have to put warnings for future devs that component would not react to changes to the as prop. It's probably too much risk for a low impact on the website's performance. Thanks for the help šŸ™‚ šŸ™
bigmistqke
bigmistqke•12mo ago
ur welcome!
duk
duk•12mo ago
You could also use document.createElement(props.as) and return that from your component if you don't need it to be dynamic. In Solid DOM and JSX nodes are interchangable.
-=Camille=-
-=Camille=-OP•12mo ago
Thank you for the advice!

Did you find this page helpful?