Last active
October 17, 2025 18:52
-
-
Save sillvva/06d350db98fb4bbf7454e5fc484a8afe to your computer and use it in GitHub Desktop.
Input Component for Remote Forms
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <script lang="ts" generics="V extends RemoteFormFieldValue"> | |
| import type { RemoteFormField, RemoteFormFieldType, RemoteFormFieldValue } from "@sveltejs/kit"; | |
| import type { HTMLInputAttributes } from "svelte/elements"; | |
| type Props = { | |
| label?: string; | |
| field: RemoteFormField<V>; | |
| description?: string; | |
| warning?: string; | |
| hidden?: boolean; | |
| } & (V extends string[] | |
| ? { type: "checkbox"; value: string } | { type: "select multiple"; value?: undefined } | |
| : V extends string | |
| ? | |
| | { type: "radio" | "submit"; value: string } | |
| | { type: "hidden"; value?: string } | |
| | { type: Exclude<RemoteFormFieldType<V>, "radio" | "hidden" | "submit">; value?: undefined } | |
| : { type: RemoteFormFieldType<V>; value?: undefined }) & | |
| Omit<HTMLInputAttributes, "type" | "id" | "value" | "name" | "checked">; | |
| let { label, field, type, value, description, warning, hidden, ...rest }: Props = $props(); | |
| const attributes = $derived( | |
| field.as( | |
| // @ts-expect-error expected | |
| type, | |
| value ?? (["string", "number"].includes(typeof field.value()) ? field.value() : undefined) | |
| ) | |
| ); | |
| const name = $derived(attributes.name); | |
| const issues = $derived(field.issues()); | |
| const invalid = $derived(!!issues?.length || undefined); | |
| </script> | |
| {#if type === "checkbox"} | |
| <label | |
| class={[ | |
| "label flex cursor-pointer rounded-lg border p-4 text-sm", | |
| invalid ? "border-error" : "border-base-content/20", | |
| hidden ? "hidden" : "" | |
| ]} | |
| > | |
| <div class="flex flex-1 flex-col gap-0.5"> | |
| <span> | |
| <span class="text-base-content">{label}</span> | |
| {#if rest.required} | |
| <span class="text-error">*</span> | |
| {/if} | |
| </span> | |
| {#if issues && issues[0]} | |
| <span class="text-error text-pretty">{issues[0].message}</span> | |
| {:else if warning} | |
| <span class="text-warning text-pretty">{warning}</span> | |
| {:else if description} | |
| <span class="text-pretty text-neutral-500">{description}</span> | |
| {/if} | |
| </div> | |
| <input {...attributes} {...rest} aria-invalid={invalid} id={name} type="checkbox" class="checkbox-primary checkbox" /> | |
| </label> | |
| {:else} | |
| {#if type !== "hidden" && !hidden} | |
| <label for={name} class="fieldset-legend"> | |
| <span> | |
| {label} | |
| {#if rest.required} | |
| <span class="text-error">*</span> | |
| {/if} | |
| </span> | |
| </label> | |
| {/if} | |
| <input | |
| {...attributes} | |
| {...rest} | |
| aria-invalid={invalid} | |
| id={name} | |
| class={[type !== "hidden" && !hidden && "input focus:border-primary w-full", hidden && "hidden"]} | |
| /> | |
| {#if type !== "hidden" && !hidden && (issues?.length || warning || description)} | |
| <label for={name} class="fieldset-label"> | |
| {#if issues && issues[0]} | |
| <span class="text-error text-pretty">{issues[0].message}</span> | |
| {:else if warning} | |
| <span class="text-warning text-pretty">{warning}</span> | |
| {:else} | |
| <span class="text-pretty text-neutral-500">{description}</span> | |
| {/if} | |
| </label> | |
| {/if} | |
| {/if} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment