Form field wrappers with built-in labels, descriptions, and error handling. Less boilerplate than field components.
About
Field components exist but they're very verbose. So there is now "f" which is a shorter version of the field components that should integrate better into laravel. These are opinionated form wrappers that combine labels, inputs, descriptions, and error messages into single components. If you don't want to write Field.Field and Field.Label and Field.Error every time, these might work better for you.
Each component handles the whole field structure internally, so you just bind a value and pass in label/error props. That's it.
Installation
Copy and paste the component files into your project.
Usage
<script lang="ts">
import { FInput, FSelect, FDate } from "$lib/components/ui/f";
let name = $state("");
let email = $state("");
let errors = $state({ name: null, email: null });
</script> <form>
<FInput
bind:value={name}
label="Name"
error={errors.name}
description="Your full name"
required
/>
<FInput bind:value={email} label="Email" error={errors.email} type="email" />
</form> Components
The package includes wrappers for most common form inputs:
FInput- Text inputsFTextarea- Multi-line textFSelect- Dropdown select with badgesFRadio- Radio button groupsFDate- Date picker with calendarFDateTime- Date and time pickerFDateRange- Date range picker with presetsFTime- Time inputFFileUpload- File upload with FilePondFSignature- Signature padFDisplay- Read-only display of valuesFRelatedSingle- Dialog-based item selector
There are also low-level components if you need them: Input, Checkbox, Description.
Examples
Text Input
Basic text input with label, description, and error support.
<script lang="ts">
let username = $state("");
let error = $state(null);
</script>
<FInput
bind:value={username}
label="Username"
description="Choose a unique username"
{error}
placeholder="evilrabbit"
required
/> Common props for all components:
label- Field labeldescription- Help text below the inputerror- Error message (shows if not null)required- Shows asterisk next to label
Textarea
Multi-line text input.
<FTextarea
bind:value={bio}
label="Bio"
description="Tell us about yourself"
rows={4}
placeholder="I'm a developer..."
/> Select
Dropdown with support for single/multiple selection and badge display.
<script lang="ts">
let role = $state("user");
const options = [
{ value: "admin", label: "Administrator" },
{ value: "user", label: "User" },
{ value: "guest", label: "Guest" },
];
</script>
<FSelect
bind:value={role}
label="Role"
{options}
type="single"
placeholder="Select a role"
/> For multiple selection:
<FSelect
bind:value={tags}
label="Tags"
{options}
type="multiple"
maxDisplayItems={3}
/> The maxDisplayItems prop controls how many badges show before it displays "+N more".
Radio Group
Radio buttons with optional additional text input.
<script lang="ts">
let choice = $state({ selectedValue: null, additionalText: null });
const options = [
{ value: "yes", label: "Yes" },
{ value: "no", label: "No" },
{ value: "other", label: "Other", additional_text_input: true },
];
</script>
<FRadio
bind:value={choice}
label="Do you agree?"
{options}
name="agreement"
required
/> If an option has additional_text_input: true, it shows a text field when selected.
Date Picker
Calendar-based date picker.
<script lang="ts">
import { CalendarDate } from "@internationalized/date";
let birthdate = $state(null);
let min = new CalendarDate(1900, 1, 1);
let max = new CalendarDate(2010, 12, 31);
</script>
<FDate
bind:value={birthdate}
label="Birth Date"
{min}
{max}
description="Must be 18 or older"
/> DateTime Picker
Date and time picker with optional presets.
<script lang="ts">
import { dateTimePresets } from "$lib/components/ui/f/dateTime";
let appointment = $state(null);
</script>
<FDateTime
bind:value={appointment}
label="Appointment"
presets={dateTimePresets}
/> The presets give quick options like "Now", "In 1 hour", "Tomorrow at 9am", etc.
Date Range
Pick a start and end date with preset ranges.
<script lang="ts">
import { dateRangePresets } from "$lib/components/ui/f/dateRange";
let range = $state(null);
</script>
<FDateRange bind:value={range} label="Date Range" presets={dateRangePresets} /> Presets include "Today", "Last 7 Days", "Last 30 Days", etc.
Time Input
Time picker that returns an object with hour, min, and sec.
<script lang="ts">
let meetingTime = $state({ hour: 9, min: 0, sec: 0 });
</script>
<FTime bind:value={meetingTime} label="Meeting Time" /> You can use the exported strToTime and timeToStr helper functions for conversions:
<script lang="ts">
import { strToTime, timeToStr } from "$lib/components/ui/f";
const time = strToTime("14:30:00"); // { hour: 14, min: 30, sec: 0 }
const str = timeToStr(time); // "14:30:00"
</script> File Upload
FilePond-based file uploader with preview support.
<script lang="ts">
let fileIds = $state(new Set());
const handleProcess = (error, file) => {
if (!error && file.serverId) {
fileIds.add(file.serverId);
}
};
const handleRemove = (error, file) => {
if (!error && file.serverId) {
fileIds.delete(file.serverId);
}
};
</script>
<FFileUpload
label="Profile Picture"
acceptedFileTypes={["image/*"]}
allowMultiple={false}
serverIds={fileIds}
onProcessFile={handleProcess}
onRemoveFile={handleRemove}
/> You'll need to set up a FilePond server endpoint to handle the actual uploads.
Signature Pad
Canvas-based signature capture.
<script lang="ts">
let signature = $state(null);
</script>
<FSignature
bind:value={signature}
label="Signature"
name="signature"
description="Sign above"
/> The value includes both the point groups (for replay) and SVG output.
Display
Read-only display of values. Good for confirmation pages or readonly forms.
<FDisplay label="Email" value={user.email} />
<FDisplay label="Roles" value={["Admin", "User", "Editor"]} /> Arrays are displayed as lists. You can also pass a snippet for custom rendering:
<FDisplay label="Status">
{#snippet children()}
<Badge variant={user.active ? "default" : "destructive"}>
{user.active ? "Active" : "Inactive"}
</Badge>
{/snippet}
</FDisplay> Related Single
Dialog-based selector for picking related items. You provide the content for the dialog.
<script lang="ts">
let selectedUserId = $state(null);
let selectedUserName = $state(null);
let isOpen = $state(false);
const selectUser = (user) => {
selectedUserId = user.id;
selectedUserName = user.name;
isOpen = false;
};
</script>
<FRelatedSingle
bind:value={selectedUserId}
bind:valLabel={selectedUserName}
bind:isOpen
label="Assigned To"
required
>
{#snippet children()}
<Table>
{#each users as user}
<TableRow onclick={() => selectUser(user)}>
<TableCell>{user.name}</TableCell>
</TableRow>
{/each}
</Table>
{/snippet}
</FRelatedSingle> The component shows a button that opens a dialog. Put whatever you want in the dialog content to let users pick something.
Validation
All components support an error prop. Just pass in your error message and it displays below the input:
<script lang="ts">
let email = $state("");
let errors = $state({});
const validate = () => {
errors = {};
if (!email.includes("@")) {
errors.email = "Enter a valid email address";
}
};
</script>
<FInput bind:value={email} label="Email" error={errors.email} type="email" /> The components don't do validation themselves - that's your job. They just display whatever error you give them.
Working with Forms
These work fine with SvelteKit form actions or client-side validation:
<script lang="ts">
import { enhance } from "$app/forms";
let form = $state({ name: "", email: "" });
let errors = $state({});
</script>
<form method="POST" use:enhance>
<FInput
bind:value={form.name}
name="name"
label="Name"
error={errors.name}
required
/>
<FInput
bind:value={form.email}
name="email"
label="Email"
error={errors.email}
type="email"
required
/>
<button type="submit">Submit</button>
</form> Or with something like Superforms:
<script lang="ts">
import { superForm } from "sveltekit-superforms";
const { form, errors } = superForm(data.form);
</script>
<FInput
bind:value={$form.username}
label="Username"
error={$errors.username?.[0]}
/> Props Reference
Common props across most components:
label?: string- Field label textdescription?: string- Help texterror?: string | null- Error messagerequired?: boolean- Show required asteriskdisabled?: boolean- Disable the inputclass?: string- Additional CSS classesref?: HTMLElement- Element reference
Component-specific props are pretty straightforward - check the TypeScript definitions or just look at the component source if you need details.
Notes
- These components use
$bindable()for two-way binding - They're opinionated and might not fit every use case
- If you need more control, use the regular
Fieldcomponents - The date/time components need
@internationalized/dateinstalled - File upload needs
svelte-filepondand plugins - Signature needs
signature_pad - NLP date needs the
nlp-date-inputcomponent
That's about it. They're just wrappers to save you some typing.