Viana Kitv0.1.4

Components

Field

A set of composable primitives for building accessible form fields — label, description, and error message — that wrap any input.

example.tsx

This is your public display name.


Import

tsx
import {
  AppField,
  AppFieldLabel,
  AppFieldDescription,
  AppFieldError,
} from "@/components/primitives/AppField"

Examples

Required

Pass required on AppFieldLabel to append a red asterisk.

example.tsx

We will never share your email.

Invalid

Use AppFieldError to show a validation error. Add border-destructive to the input to complete the visual.

example.tsx

Username must be at least 3 characters.

Grid

Compose multiple fields in a CSS grid for multi-column layouts.

example.tsx

With badge

Place an AppBadge next to the label to signal optional or beta fields.

example.tsx
Optional

Leave blank to use the default key.

Input group

Attach a static prefix or suffix to the input using a bordered span and rounded-l-none.

example.tsx
https://

Enter your domain without the protocol.

Button group

Pair an input with a button using a flex wrapper.

example.tsx

Search group

example.tsx

Search across all available components.

API Reference

AppField

A flex column container with gap-1.5. Accepts all <div> attributes.

AppFieldLabel

PropTypeDefaultDescription
requiredbooleanfalseAppends a red asterisk after the label text.
htmlForstringAssociates the label with an input by id.
classNamestringAdditional Tailwind classes merged via cn().

AppFieldDescription & AppFieldError

Both render a <p> and accept all paragraph HTML attributes. AppFieldDescription uses text-muted-foreground. AppFieldError uses text-destructive.

Source

src/components/primitives/AppField.tsx
"use client"

import * as React from "react"
import { Label } from "@/components/ui/label"
import { cn } from "@/lib/utils"

function AppField({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
  return <div className={cn("flex flex-col gap-1.5", className)} {...props} />
}

type AppFieldLabelProps = React.ComponentPropsWithoutRef<typeof Label> & {
  required?: boolean
}

const AppFieldLabel = React.forwardRef<
  React.ComponentRef<typeof Label>,
  AppFieldLabelProps
>(({ className, required, children, ...props }, ref) => (
  <Label ref={ref} className={cn(className)} {...props}>
    {children}
    {required && <span className="text-destructive">*</span>}
  </Label>
))
AppFieldLabel.displayName = "AppFieldLabel"

const AppFieldDescription = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
  <p ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
))
AppFieldDescription.displayName = "AppFieldDescription"

const AppFieldError = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
  <p ref={ref} className={cn("text-sm text-destructive", className)} {...props} />
))
AppFieldError.displayName = "AppFieldError"

export { AppField, AppFieldLabel, AppFieldDescription, AppFieldError }
export type { AppFieldLabelProps }