Field
Label, hint and error around a control.
We'll only use this for event updates.
Tell us a little more.
Code
Copy into src/components/ph/ .
Field.astro
---
import Icon from "./Icon.astro";
type Props = {
label: string;
for?: string;
hint?: string;
error?: string;
class?: string;
};
const { label, for: htmlFor, hint, error, class: className } = Astro.props;
---
<div class:list={["flex flex-col gap-1.5", className]}>
<label for={htmlFor} class="ph-subheadline text-[12px]">{label}</label>
<slot />
{
error ? (
<p class="flex items-center gap-1.5 text-[13px]">
<Icon name="exclamation-triangle" class="size-3.5 text-ph-orange" />
{error}
</p>
) : (
hint && <p class="text-[13px]">{hint}</p>
)
}
</div>
Copy into components/ph/ (or src/components/ph/).
field.tsx
import type { ReactNode } from "react";
import { cn } from "./cn";
import { Icon } from "./icon";
type FieldProps = {
label: string;
htmlFor?: string;
hint?: string;
error?: string;
children: ReactNode;
className?: string;
};
export function Field({ label, htmlFor, hint, error, children, className }: FieldProps) {
return (
<div className={cn("flex flex-col gap-1.5", className)}>
<label htmlFor={htmlFor} className="ph-subheadline text-[12px]">
{label}
</label>
{children}
{error ? (
<p className="flex items-center gap-1.5 text-[13px]">
<Icon name="exclamation-triangle" className="size-3.5 text-ph-orange" />
{error}
</p>
) : (
hint && <p className="text-[13px]">{hint}</p>
)}
</div>
);
}
cn.ts
export const cn = (...parts: (string | false | null | undefined)[]) => parts.filter(Boolean).join(" ");