Bottom sheet picker
Choose a value from a sheet.
bottom-sheet-picker.tsx
"use client";
import { useState, type SyntheticEvent } from "react";
import { LuChevronRight } from "react-icons/lu";
import {
Alert,
BottomSheet,
Button,
Input,
RadioField,
RadioGroup,
Textarea,
TopAppBar,
} from "@nexera-ui/react";
const LEAVE_TYPES = [
{ id: "annual", label: "Annual leave", description: "14 of 25 days left" },
{ id: "sick", label: "Sick leave", description: "No limit · note needed after 3 days" },
{ id: "parental", label: "Parental leave", description: "Up to 26 weeks, paid at 90%" },
{ id: "unpaid", label: "Unpaid leave", description: "Needs approval from your manager" },
{ id: "study", label: "Study leave", description: "5 days left for exams this year" },
] as const;
/** Bottom sheet picker: choose the leave type from a sheet while filling in a request on a phone. */
export default function BottomSheetPicker() {
const [type, setType] = useState<string>("annual");
const [sent, setSent] = useState(false);
const current = LEAVE_TYPES.find((item) => item.id === type) ?? LEAVE_TYPES[0];
const onSubmit = (event: SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
setSent(true); // replace with your request
};
return (
<div className="@container bg-page px-4 py-8">
<div className="mx-auto flex w-full max-w-sm flex-col overflow-hidden rounded-xl border border-default bg-page shadow-md">
<TopAppBar
title="Request leave"
headingLevel={2}
platform="ios"
leading="close"
leadingLabel="Close"
leadingHref="#home"
/>
<form className="grid gap-5 px-4 pt-2 pb-6" onSubmit={onSubmit}>
{sent ? (
<Alert
tone="success"
title={`${current.label} requested`}
description="Mia Jensen will review it. This is a demo."
/>
) : null}
<div className="grid gap-2">
<span id="bsp-leave-type-label" className="text-component-label text-primary">
Leave type
</span>
<BottomSheet
title="Leave type"
platform="ios"
trigger={
<Button
platform="ios"
variant="secondary"
size="lg"
trailingIcon={<LuChevronRight />}
aria-labelledby="bsp-leave-type-label bsp-leave-type-value"
className="w-full justify-between"
>
<span id="bsp-leave-type-value">{current.label}</span>
</Button>
}
footer={
<Button platform="ios" size="lg" slot="close" className="w-full">
Done
</Button>
}
>
<RadioGroup aria-label="Leave type" value={type} onChange={setType}>
{LEAVE_TYPES.map((item) => (
<RadioField
key={item.id}
value={item.id}
label={item.label}
description={item.description}
/>
))}
</RadioGroup>
</BottomSheet>
<p className="text-body-small text-secondary">{current.description}</p>
</div>
<div className="grid grid-cols-2 gap-3">
<Input
label="From"
type="date"
name="from"
platform="ios"
defaultValue="2026-10-20"
isRequired
/>
<Input
label="To"
type="date"
name="to"
platform="ios"
defaultValue="2026-10-24"
isRequired
/>
</div>
<Textarea
label="Note for your manager"
name="note"
placeholder="Visiting family in Lisbon"
/>
<Button type="submit" platform="ios" size="lg" className="w-full">
Send request
</Button>
</form>
</div>
</div>
);
}