S
SolidJS16mo ago
hel.io

How to create a generic Input when passing prop `class` to override styles?

Hi, I'm trying to create a generic input. I'm using Tailwindcss for the styling with cva (class-variance-authority) which allows me to create variants. I want to allow users to pass class to override the input. I have this component:
import { JSX, mergeProps } from 'solid-js';
import { VariantProps } from 'class-variance-authority';
import { inputStyles } from './inputStyles';

export type InputProps = JSX.InputHTMLAttributes<HTMLInputElement> &
JSX.InputHTMLAttributes<HTMLLabelElement> &
VariantProps<typeof inputStyles>;

export const Input = (props: InputProps) => {
const merged = mergeProps({ type: 'text' }, props);
const { size = 'md', ...inputProps } = merged;
return (
<div class="flex flex-col">
<label class="text-gray-400" for={props.id}>
{props.placeholder}
</label>
<input class={`${inputStyles({ size })} ${props.class}`} {...inputProps} />
</div>
);
};
import { JSX, mergeProps } from 'solid-js';
import { VariantProps } from 'class-variance-authority';
import { inputStyles } from './inputStyles';

export type InputProps = JSX.InputHTMLAttributes<HTMLInputElement> &
JSX.InputHTMLAttributes<HTMLLabelElement> &
VariantProps<typeof inputStyles>;

export const Input = (props: InputProps) => {
const merged = mergeProps({ type: 'text' }, props);
const { size = 'md', ...inputProps } = merged;
return (
<div class="flex flex-col">
<label class="text-gray-400" for={props.id}>
{props.placeholder}
</label>
<input class={`${inputStyles({ size })} ${props.class}`} {...inputProps} />
</div>
);
};
Ant then I call the component like so
<Input placeholder="Password" size="md" class="text-pink-300" type="password" />
<Input placeholder="Password" size="md" class="text-pink-300" type="password" />
The problem here is that if I try to extract class from props const { size, class, ...inputProps } = merged; I get an error: Unexpected keyword 'class'. I know that class is a reserved word in JavaScript. However, if I try to use className then I get this error: Property 'className' does not exist on type { ... }; Is there a way to pass a class or should I rename the prop as something else?
3 Replies
Max
Max16mo ago
Hi you can extract class by renaming it
const { size = "md", class: userClass, ...inputProps } = merged;
const { size = "md", class: userClass, ...inputProps } = merged;
then pass it like normal
<input class={`${inputStyles({ size })} ${userClass}`} {...inputProps} />
<input class={`${inputStyles({ size })} ${userClass}`} {...inputProps} />
But you still will have problem with reactivity if you destructure props like that, same with size=md should be in mergeProps. You can use built in solid helper something like this
const merged = mergeProps({ type: "text", size: "md" }, props);
const [selectedProps, restInputProps] = splitProps(merged, ["class", "size"]);
const merged = mergeProps({ type: "text", size: "md" }, props);
const [selectedProps, restInputProps] = splitProps(merged, ["class", "size"]);
then when rendering
<input
class={`${inputStyles({ size: selectedProps.size })} ${
selectedProps.class
}`}
{...restInputProps}
/>
<input
class={`${inputStyles({ size: selectedProps.size })} ${
selectedProps.class
}`}
{...restInputProps}
/>
hel.io
hel.io16mo ago
Hi @maxoucsgo, Thank you very much for your reply. I didn't know about splitProps , this solved my problem.
Max
Max16mo ago
Nice! np