An interactive demonstration of advanced data entry and edit layouts. Compare inline editing, multi-card forms, side-by-side splits, and dense grids.
Support Ticket Form Laboratory
Compare ticket form layouts: inline-editable panels with dropdown selectors, sectioned dashboard cards, split details view, or compact inputs grids.
Inline editable form — all fields toggle between read-only and editable
Variant1_InlineEditable.tsx (Widget Implementation)
import { useState } from "react";
import {
Box,
Button,
Group,
Paper,
Select,
Stack,
Text,
Textarea,
TextInput,
Title,
Transition,
Divider,
} from "@mantine/core";
import { HiPencilSquare, HiCheck, HiArrowPath, HiXMark } from "react-icons/hi2";
import type { SupportTicketFormProps, SupportTicket } from "./types";
import {
statusOptions,
priorityOptions,
categoryOptions,
severityOptions,
environmentOptions,
userOptions,
toolOptions,
releaseTargetOptions,
} from "./sampleData";
export function Variant1_InlineEditable({ ticket, onSave }: SupportTicketFormProps) {
const [isEditing, setIsEditing] = useState(false);
const [formData, setFormData] = useState<SupportTicket>({ ...ticket });
const [originalData, setOriginalData] = useState<SupportTicket>({
...ticket,
});
const handleEdit = () => setIsEditing(true);
const handleCancel = () => {
setFormData({ ...originalData });
setIsEditing(false);
};
const handleReset = () => {
setFormData({ ...originalData });
};
const handleSubmit = () => {
onSave(formData);
setOriginalData({ ...formData });
setIsEditing(false);
};
const updateField = <K extends keyof SupportTicket>(field: K, value: SupportTicket[K]) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};
const inputStyles = {
input: {
backgroundColor: isEditing ? undefined : "var(--mantine-color-gray-1)",
},
};
return (
<Box style={{ height: "100%", display: "flex", flexDirection: "column" }} p="md">
<Paper shadow="xs" p="lg" radius="md" withBorder>
{/* Header */}
<Group justify="space-between" mb="lg">
<div>
<Title order={3}>Support Ticket: {originalData.id}</Title>
<Text size="sm" c="dimmed">
Inline editable form — all fields toggle between read-only and editable
</Text>
</div>
{!isEditing && (
<Button leftSection={<HiPencilSquare size={16} />} onClick={handleEdit}>
Edit
</Button>
)}
</Group>
<Divider mb="lg" />
{/* Form Fields */}
<Stack gap="md">
<TextInput
label="Title"
value={formData.title}
onChange={(e) => updateField("title", e.currentTarget.value)}
readOnly={!isEditing}
styles={inputStyles}
/>
<Textarea
label="Description"
value={formData.description}
onChange={(e) => updateField("description", e.currentTarget.value)}
readOnly={!isEditing}
minRows={3}
autosize
styles={inputStyles}
/>
<Group grow>
<Select
label="Status"
value={formData.status}
onChange={(val) => updateField("status", val as SupportTicket["status"])}
data={statusOptions}
readOnly={!isEditing}
styles={inputStyles}
/>
<Select
label="Priority"
value={formData.priority}
onChange={(val) => updateField("priority", val as SupportTicket["priority"])}
data={priorityOptions}
readOnly={!isEditing}
styles={inputStyles}
/>
</Group>
<Group grow>
<Select
label="Assigned To"
value={formData.assignedTo}
onChange={(val) => updateField("assignedTo", val ?? "")}
data={userOptions}
readOnly={!isEditing}
styles={inputStyles}
/>
<Select
label="Submitted By"
value={formData.submittedBy}
data={userOptions}
readOnly
styles={{
input: {
backgroundColor: "var(--mantine-color-gray-1)",
},
}}
/>
</Group>
<Group grow>
<Select
label="Category"
value={formData.category}
onChange={(val) => updateField("category", val as SupportTicket["category"])}
data={categoryOptions}
readOnly={!isEditing}
styles={inputStyles}
/>
<Select
label="Severity"
value={formData.severity}
onChange={(val) => updateField("severity", val as SupportTicket["severity"])}
data={severityOptions}
readOnly={!isEditing}
styles={inputStyles}
/>
</Group>
<Group grow>
<Select
label="Tool / Application"
value={formData.toolApplication}
onChange={(val) => updateField("toolApplication", val ?? "")}
data={toolOptions}
readOnly={!isEditing}
styles={inputStyles}
/>
<Select
label="Environment"
value={formData.environment}
onChange={(val) => updateField("environment", val as SupportTicket["environment"])}
data={environmentOptions}
readOnly={!isEditing}
styles={inputStyles}
/>
</Group>
<Group grow>
<Select
label="Release Target"
value={formData.releaseTarget}
onChange={(val) => updateField("releaseTarget", val ?? "")}
data={releaseTargetOptions}
readOnly={!isEditing}
styles={inputStyles}
/>
<div />
</Group>
</Stack>
{/* Action Buttons — hidden when not editing */}
<Transition mounted={isEditing} transition="fade" duration={200}>
{(styles) => (
<Group justify="flex-end" mt="xl" style={styles}>
<Button
variant="subtle"
color="gray"
leftSection={<HiXMark size={16} />}
onClick={handleCancel}
>
Cancel
</Button>
<Button variant="light" leftSection={<HiArrowPath size={16} />} onClick={handleReset}>
Reset
</Button>
<Button leftSection={<HiCheck size={16} />} onClick={handleSubmit}>
Submit
</Button>
</Group>
)}
</Transition>
</Paper>
</Box>
);
}