Closed nsaunders closed 3 years ago
Yeah, we use this trick with our styled components implementation. The easiest way is to use the <Dynamic>
tag internally. https://www.solidjs.com/tutorial/flow_dynamic
To clarify dynamic can take a string tag as well like a
as the component={}
^Like what he said.
If you're using TypeScript, however, it gets very complex. You can refer to solid-headless' way of type inference for Polymorphic components: https://github.com/LXSMNSYC/solid-headless/blob/main/packages/solid-headless/src/utils/dynamic-prop.ts
Wonderful, thanks @ryansolid and @LXSMNSYC for the responses!
Hi, for other people that want to do it, here is a basic implementation adapted from this react version :
import { Dynamic, render } from "solid-js/web";
import { Component, ComponentProps, JSX, splitProps } from "solid-js";
type ElementType = keyof JSX.IntrinsicElements | Component<any>;
type BoxProps<T extends ElementType> = {
as?: T,
children?: JSX.Element
}
function Box<T extends ElementType = "div">(props: BoxProps<T> & Omit<ComponentProps<T>, keyof BoxProps<T>>) {
const [local, others] = splitProps(props, ["as"]);
const component = local.as || "div"
return <Dynamic component={component} {...others} />
}
Usage example :
function RedThing(props: { text: string }) {
return <strong style="color: red">{props.text}</strong>;
}
function App() {
let inputRef : HTMLInputElement | null = null;
const focusInput = () => {
inputRef?.focus()
}
return (
<Box as="main">
<Box as={RedThing} text="hello" />
<Box as="a" href="https://solidjs.com">go to solidjs website</Box>
<Box as="input" ref={inputRef} />
<Box as="button" onClick={focusInput}>Focus input</Box>
</Box>
);
}
render(() => <App />, document.getElementById("app"));
Hi, is it possible to implement polymorphic components using SolidJS? For anyone who might be unaware, polymorphic components are a common pattern in React, where a prop like
as
orcomponent
allows you to control what HTML tag is used in the rendered output, i.e.<Link as="a" href="...">...</Link>
or<Link as="button" type="submit">...</Link>
.