1import { createSignal } from "solid-js";2
3import {4 TextField,5 TextFieldDescription,6 TextFieldErrorMessage,7 TextFieldInput,8 TextFieldLabel,9} from "~/components/ui/text-field";10
11export default function TextFieldDemo() {12 const [name, setName] = createSignal("");13
14 return (15 <TextField16 value={name()}17 onChange={setName}18 validationState={name().length < 3 ? "invalid" : "valid"}19 >20 <TextFieldLabel>Name</TextFieldLabel>21 <TextFieldInput type="text" />22 <TextFieldDescription>Please enter your full name.</TextFieldDescription>23 <TextFieldErrorMessage>24 Name must be at least 3 characters long.25 </TextFieldErrorMessage>26 </TextField>27 );28}
npx shadcn@latest add https://solid-ui-neobrutalism.vercel.app/r/text-field.json
yarn shadcn@latest add https://solid-ui-neobrutalism.vercel.app/r/text-field.json
pnpm dlx shadcn@latest add https://solid-ui-neobrutalism.vercel.app/r/text-field.json
bunx --bun shadcn@latest add https://solid-ui-neobrutalism.vercel.app/r/text-field.json
Install the following dependencies
npm install @kobalte/core
yarn add @kobalte/core
pnpm add @kobalte/core
bun add @kobalte/core
Copy and paste the following code into your project
1import type { PolymorphicProps } from "@kobalte/core";2import type { ValidComponent } from "solid-js";3
4import { mergeProps, splitProps } from "solid-js";5import * as TextFieldPrimitive from "@kobalte/core/text-field";6import { cva } from "class-variance-authority";7
8import { cn } from "~/lib/utils";9
10type TextFieldRootProps<T extends ValidComponent = "div"> =11 TextFieldPrimitive.TextFieldRootProps<T> & {12 class?: string | undefined;13 };14
15const TextField = <T extends ValidComponent = "div">(16 props: PolymorphicProps<T, TextFieldRootProps<T>>,17) => {18 const [local, others] = splitProps(props as TextFieldRootProps, ["class"]);19 return (20 <TextFieldPrimitive.Root21 data-slot="text-field"22 class={cn("flex flex-col gap-1", local.class)}23 {...others}24 />25 );26};27
28type TextFieldInputProps<T extends ValidComponent = "input"> =29 TextFieldPrimitive.TextFieldInputProps<T> & {30 class?: string | undefined;31 type?:32 | "button"33 | "checkbox"34 | "color"35 | "date"36 | "datetime-local"37 | "email"38 | "file"39 | "hidden"40 | "image"41 | "month"42 | "number"43 | "password"44 | "radio"45 | "range"46 | "reset"47 | "search"48 | "submit"49 | "tel"50 | "text"51 | "time"52 | "url"53 | "week";54 };55
56const TextFieldInput = <T extends ValidComponent = "input">(57 rawProps: PolymorphicProps<T, TextFieldInputProps<T>>,58) => {59 const props = mergeProps<TextFieldInputProps<T>[]>(60 { type: "text" },61 rawProps,62 );63 const [local, others] = splitProps(props as TextFieldInputProps, [64 "type",65 "class",66 ]);67 return (68 <TextFieldPrimitive.Input69 data-slot="text-field-input"70 type={local.type}71 class={cn(72 "flex h-10 w-full rounded-base border-2 border-border bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 ui-invalid:border-error-foreground ui-invalid:text-error-foreground",73 local.class,74 )}75 {...others}76 />77 );78};79
80type TextFieldTextAreaProps<T extends ValidComponent = "textarea"> =81 TextFieldPrimitive.TextFieldTextAreaProps<T> & { class?: string | undefined };82
83const TextFieldTextArea = <T extends ValidComponent = "textarea">(84 props: PolymorphicProps<T, TextFieldTextAreaProps<T>>,85) => {86 const [local, others] = splitProps(props as TextFieldTextAreaProps, [87 "class",88 ]);89 return (90 <TextFieldPrimitive.TextArea91 data-slot="text-field-textarea"92 class={cn(93 "flex min-h-[80px] w-full rounded-base border-2 border-border bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",94 local.class,95 )}96 {...others}97 />98 );99};100
101const labelVariants = cva(102 "text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70",103 {104 variants: {105 variant: {106 label: "data-[invalid]:text-destructive",107 description: "font-normal text-muted-foreground",108 error: "text-xs text-error-foreground",109 },110 },111 defaultVariants: {112 variant: "label",113 },114 },115);116
117type TextFieldLabelProps<T extends ValidComponent = "label"> =118 TextFieldPrimitive.TextFieldLabelProps<T> & { class?: string | undefined };119
120const TextFieldLabel = <T extends ValidComponent = "label">(121 props: PolymorphicProps<T, TextFieldLabelProps<T>>,122) => {123 const [local, others] = splitProps(props as TextFieldLabelProps, ["class"]);124 return (125 <TextFieldPrimitive.Label126 data-slot="text-field-label"127 class={cn(labelVariants(), local.class)}128 {...others}129 />130 );131};132
133type TextFieldDescriptionProps<T extends ValidComponent = "div"> =134 TextFieldPrimitive.TextFieldDescriptionProps<T> & {135 class?: string | undefined;136 };137
138const TextFieldDescription = <T extends ValidComponent = "div">(139 props: PolymorphicProps<T, TextFieldDescriptionProps<T>>,140) => {141 const [local, others] = splitProps(props as TextFieldDescriptionProps, [142 "class",143 ]);144 return (145 <TextFieldPrimitive.Description146 data-slot="text-field-description"147 class={cn(labelVariants({ variant: "description" }), local.class)}148 {...others}149 />150 );151};152
153type TextFieldErrorMessageProps<T extends ValidComponent = "div"> =154 TextFieldPrimitive.TextFieldErrorMessageProps<T> & {155 class?: string | undefined;156 };157
158const TextFieldErrorMessage = <T extends ValidComponent = "div">(159 props: PolymorphicProps<T, TextFieldErrorMessageProps<T>>,160) => {161 const [local, others] = splitProps(props as TextFieldErrorMessageProps, [162 "class",163 ]);164 return (165 <TextFieldPrimitive.ErrorMessage166 data-slot="text-field-error-message"167 class={cn(labelVariants({ variant: "error" }), local.class)}168 {...others}169 />170 );171};172
173export {174 TextField,175 TextFieldInput,176 TextFieldTextArea,177 TextFieldLabel,178 TextFieldDescription,179 TextFieldErrorMessage,180};
Update the import paths to match your project setup.
1import {2 TextField,3 TextFieldDescription,4 TextFieldErrorMessage,5 TextFieldInput,6 TextFieldLabel,7 TextFieldTextArea,8} from "~/components/ui/text-field";
1<TextField>2 <TextFieldLabel>Name</TextFieldLabel>3 <TextFieldInput />4</TextField>
Use TextFieldTextArea
instead of TextFieldInput
for multiline input fields.
1import {2 TextField,3 TextFieldLabel,4 TextFieldTextArea,5} from "~/components/ui/text-field";6
7export default function TextFieldDemo() {8 return (9 <TextField>10 <TextFieldLabel>Text</TextFieldLabel>11 <TextFieldTextArea class="w-64" />12 </TextField>13 );14}