Flight Search
A travel booking page with search form, filters, and flight results.
Preview
Open full demoPrices are lower than usual!
United Airlines
UA 1234
6:30 AM
LAX
2:45 PM
JFK
$328
per person
Route
LAX → JFK
Aircraft: Boeing 737-800
Baggage
Carry-on: 7kg included
Checked: 23kg included
Fare Rules
Cancellation: Free within 24h
Changes: $50 fee applies
Delta Air Lines
DL 890
9:15 AM
LAX
6:30 PM
JFK
$356
per person
Route
LAX → JFK
Aircraft: Boeing 737-800
Baggage
Carry-on: 7kg included
Checked: 23kg included
Fare Rules
Cancellation: Free within 24h
Changes: $50 fee applies
JetBlue
B6 421
11:00 AM
LAX
10:20 PM
JFK
$249
per person
Route
LAX → JFK
Aircraft: Boeing 737-800
Baggage
Carry-on: 7kg included
Checked: 23kg included
Fare Rules
Cancellation: Free within 24h
Changes: $50 fee applies
Popular Destinations
Tokyo
From $699
Paris
From $449
Bali
From $549
Interactive Demo
This app demo is best experienced in full-screen mode on mobile devices. Tap below to open the interactive demo.
Code
<div class="flex flex-col h-full overflow-hidden">
@* Top Navigation *@
<BbResponsiveNavProvider>
<header class="flex items-center justify-between px-4 py-2.5 border-b">
<div class="flex items-center gap-4">
<BbResponsiveNavTrigger Class="md:hidden" />
<div class="flex items-center gap-2">
<div class="flex h-7 w-7 items-center justify-center rounded-md bg-primary text-primary-foreground">
<LucideIcon Name="plane" class="h-4 w-4" />
</div>
<span class="text-sm font-semibold">SkySearch</span>
</div>
<BbTabs @bind-Value="_activeTab" Class="hidden md:block">
<BbTabsList Class="h-8">
<BbTabsTrigger Value="flights" Class="text-xs px-3">
<LucideIcon Name="plane" class="h-3 w-3 mr-1" />
Flights
</BbTabsTrigger>
<BbTabsTrigger Value="hotels" Class="text-xs px-3">
<LucideIcon Name="building-2" class="h-3 w-3 mr-1" />
Hotels
</BbTabsTrigger>
<BbTabsTrigger Value="cars" Class="text-xs px-3">
<LucideIcon Name="car" class="h-3 w-3 mr-1" />
Car Rental
</BbTabsTrigger>
</BbTabsList>
</BbTabs>
</div>
<div class="flex items-center gap-2">
<BbAvatar Size="AvatarSize.Small" Class="h-7 w-7">
<BbAvatarFallback Class="text-[10px] bg-primary/10 text-primary">AJ</BbAvatarFallback>
</BbAvatar>
<span class="text-xs hidden md:block">Alex Johnson</span>
</div>
</header>
<BbResponsiveNavContent>
<nav class="flex flex-col gap-4 p-4">
<a href="#" class="text-sm font-medium">Flights</a>
<a href="#" class="text-sm text-muted-foreground">Hotels</a>
<a href="#" class="text-sm text-muted-foreground">Car Rental</a>
</nav>
</BbResponsiveNavContent>
</BbResponsiveNavProvider>
<div class="flex-1 overflow-auto">
@if (_activeTab == "hotels")
{
<div class="flex-1 flex items-center justify-center p-12">
<BbEmpty Title="Hotel search coming soon"
Description="We're working on bringing you the best hotel deals. Check back later!">
<Icon>
<LucideIcon Name="building-2" class="h-10 w-10" />
</Icon>
</BbEmpty>
</div>
}
else if (_activeTab == "cars")
{
<div class="flex-1 flex items-center justify-center p-12">
<BbEmpty Title="Car rental search coming soon"
Description="We're working on bringing you the best car rental options. Check back later!">
<Icon>
<LucideIcon Name="car" class="h-10 w-10" />
</Icon>
</BbEmpty>
</div>
}
else
{
<div class="p-4 md:p-6 space-y-5">
@* Breadcrumb *@
<BbBreadcrumb>
<BbBreadcrumbList>
<BbBreadcrumbItem>
<BbBreadcrumbLink Href="#">Home</BbBreadcrumbLink>
</BbBreadcrumbItem>
<BbBreadcrumbSeparator />
<BbBreadcrumbItem>
<BbBreadcrumbLink Href="#">Flights</BbBreadcrumbLink>
</BbBreadcrumbItem>
<BbBreadcrumbSeparator />
<BbBreadcrumbItem>
<BbBreadcrumbPage>Search Results</BbBreadcrumbPage>
</BbBreadcrumbItem>
</BbBreadcrumbList>
</BbBreadcrumb>
@* Search Form *@
<BbCard>
<BbCardContent Class="p-4 pt-5 md:p-6 md:pt-7">
<div class="space-y-4">
@* Trip Type *@
<BbRadioGroup TValue="string" Value=@("roundtrip") Class="flex gap-4">
<div class="flex items-center gap-1.5">
<BbRadioGroupItem Value=@("roundtrip") Id="trip-round" />
<BbLabel For="trip-round" Class="text-sm font-normal cursor-pointer">Round trip</BbLabel>
</div>
<div class="flex items-center gap-1.5">
<BbRadioGroupItem Value=@("oneway") Id="trip-one" />
<BbLabel For="trip-one" Class="text-sm font-normal cursor-pointer">One way</BbLabel>
</div>
<div class="flex items-center gap-1.5">
<BbRadioGroupItem Value=@("multi") Id="trip-multi" />
<BbLabel For="trip-multi" Class="text-sm font-normal cursor-pointer">Multi-city</BbLabel>
</div>
</BbRadioGroup>
@* Search Fields *@
<div class="grid gap-3 md:grid-cols-2 lg:grid-cols-[1fr_1fr_1fr_auto_auto]">
<div class="space-y-1.5">
<span class="text-xs font-medium">From</span>
<BbCombobox TValue="string"
Options="@_airportOptions"
@bind-Value="originValue"
Placeholder="Origin airport"
SearchPlaceholder="Search airports..."
EmptyMessage="No airports found"
Class="h-10 w-full" />
</div>
<div class="space-y-1.5">
<span class="text-xs font-medium">To</span>
<BbCombobox TValue="string"
Options="@_airportOptions"
@bind-Value="destValue"
Placeholder="Destination"
SearchPlaceholder="Search airports..."
EmptyMessage="No airports found"
Class="h-10 w-full" />
</div>
<div class="space-y-1.5">
<span class="text-xs font-medium">Dates</span>
<BbDateRangePicker Placeholder="Select dates" Class="h-10 w-full" />
</div>
<div class="space-y-1.5">
<span class="text-xs font-medium">Passengers</span>
<BbNumericInput TValue="int" Value="1" Min="1" Max="9" ShowButtons="true" Class="h-10 w-20" />
</div>
<div class="space-y-1.5">
<span class="text-xs font-medium">Class</span>
<BbSelect TValue="string" Value=@("Economy")>
<BbSelectTrigger Class="h-10 w-full md:w-[130px]">
<BbSelectValue Placeholder="Class" />
</BbSelectTrigger>
<BbSelectContent>
<BbSelectItem TValue="string" Value=@("Economy")>Economy</BbSelectItem>
<BbSelectItem TValue="string" Value=@("Business")>Business</BbSelectItem>
<BbSelectItem TValue="string" Value=@("First")>First</BbSelectItem>
</BbSelectContent>
</BbSelect>
</div>
</div>
<BbButton Class="w-full md:w-auto">
<LucideIcon Name="search" class="mr-2 h-4 w-4" />
Search Flights
</BbButton>
</div>
</BbCardContent>
</BbCard>
@* Loading State *@
<div class="flex items-center gap-3">
<BbSpinner Class="h-4 w-4" />
<BbProgress Value="65" Class="flex-1" />
<span class="text-xs text-muted-foreground">Searching 200+ airlines...</span>
</div>
@* Deal Alert *@
<BbAlert Variant="AlertVariant.Info">
<BbAlertTitle>
<LucideIcon Name="trending-down" class="inline h-4 w-4 mr-1" />
Prices are lower than usual!
</BbAlertTitle>
<BbAlertDescription>Flights on this route are 18% cheaper than average. Book soon to lock in this price.</BbAlertDescription>
</BbAlert>
@* Results Layout *@
<div class="grid gap-6 lg:grid-cols-[280px_1fr] pt-4 lg:pt-0">
@* Filters Panel *@
<div class="space-y-5 hidden lg:block">
<h3 class="text-sm font-semibold">Filters</h3>
@* Price Range *@
<div class="space-y-2">
<div class="flex items-center justify-between">
<span class="text-xs font-medium">Price Range</span>
<BbTooltip>
<BbTooltipTrigger>
<LucideIcon Name="info" class="h-3.5 w-3.5 text-muted-foreground" />
</BbTooltipTrigger>
<BbTooltipContent>
<span>Filter by total price per person</span>
</BbTooltipContent>
</BbTooltip>
</div>
<BbRangeSlider @bind-Value="priceRange" Min="0" Max="2000" Step="50" ShowTooltips="true" FormatValueFunc="@(v => $"${v:F0}")" />
<div class="flex justify-between text-[10px] text-muted-foreground">
<span>[email protected]("F0")</span>
<span>[email protected]("F0")</span>
</div>
</div>
<BbSeparator />
@* Stops *@
<div class="space-y-2">
<span class="text-xs font-medium">Stops</span>
<div class="space-y-2">
<div class="flex items-center gap-2">
<BbCheckbox Id="stops-0" Checked="true" />
<BbLabel For="stops-0" Class="text-xs font-normal cursor-pointer">Non-stop</BbLabel>
</div>
<div class="flex items-center gap-2">
<BbCheckbox Id="stops-1" Checked="true" />
<BbLabel For="stops-1" Class="text-xs font-normal cursor-pointer">1 stop</BbLabel>
</div>
<div class="flex items-center gap-2">
<BbCheckbox Id="stops-2" />
<BbLabel For="stops-2" Class="text-xs font-normal cursor-pointer">2+ stops</BbLabel>
</div>
</div>
</div>
<BbSeparator />
@* Airlines *@
<div class="space-y-2">
<span class="text-xs font-medium">Airlines</span>
<BbMultiSelect TValue="string"
Options="@_airlineOptions"
@bind-Values="selectedAirlines"
Placeholder="All airlines"
MaxDisplayTags="2"
MatchTriggerWidth="true"
Class="w-full" />
</div>
<BbSeparator />
@* Departure Time *@
<div class="space-y-2">
<span class="text-xs font-medium">Departure After</span>
<BbTimePicker @bind-Value="departureTime" Placeholder="Any time" />
</div>
<BbSeparator />
@* Max Duration *@
<div class="space-y-2">
<div class="flex items-center justify-between">
<span class="text-xs font-medium">Max Duration</span>
<span class="text-xs text-muted-foreground">@durationHours.ToString("F0")h</span>
</div>
<BbSlider @bind-Value="durationHours" Min="2" Max="24" Step="1" />
</div>
<BbSeparator />
@* Toggle filters *@
<div class="flex items-center justify-between">
<span class="text-xs font-medium">Direct flights only</span>
<BbSwitch />
</div>
<BbSeparator />
@* Budget *@
<div class="space-y-2">
<span class="text-xs font-medium">Max Budget</span>
<BbCurrencyInput @bind-Value="budget" CurrencyCode="USD" Placeholder="Max budget" />
</div>
@* Frequent Flyer *@
<div class="space-y-2">
<span class="text-xs font-medium">Frequent Flyer #</span>
<BbMaskedInput @bind-Value="ffNumber" Mask="AAA-999999999" Placeholder="ABC-123456789" />
</div>
<div class="flex gap-2">
<BbButton Class="flex-1" Size="ButtonSize.Small">Apply</BbButton>
<BbButton Variant="ButtonVariant.Outline" Size="ButtonSize.Small">Clear</BbButton>
</div>
</div>
@* Mobile Filters Drawer *@
<div class="lg:hidden mb-4">
<BbDrawer Direction="DrawerDirection.Bottom">
<BbDrawerTrigger>
<BbButton Variant="ButtonVariant.Outline" Class="w-full">
<LucideIcon Name="sliders-horizontal" class="mr-2 h-4 w-4" />
Filters
</BbButton>
</BbDrawerTrigger>
<BbDrawerContent>
<BbDrawerHeader>
<BbDrawerTitle>Filters</BbDrawerTitle>
<BbDrawerDescription>Narrow down your flight results</BbDrawerDescription>
</BbDrawerHeader>
<div class="p-4 space-y-4">
<div class="space-y-2">
<span class="text-xs font-medium">Price Range</span>
<BbRangeSlider @bind-Value="priceRange" Min="0" Max="2000" Step="50" />
</div>
<div class="flex items-center justify-between">
<span class="text-xs">Direct flights only</span>
<BbSwitch />
</div>
</div>
<BbDrawerFooter>
<BbButton Class="w-full">Apply Filters</BbButton>
<BbDrawerClose>
<BbButton Variant="ButtonVariant.Outline" Class="w-full">Cancel</BbButton>
</BbDrawerClose>
</BbDrawerFooter>
</BbDrawerContent>
</BbDrawer>
</div>
@* Results *@
<div class="space-y-4">
@* Sort *@
<div class="flex items-center justify-between">
<span class="text-sm text-muted-foreground">24 flights found</span>
<div class="flex items-center gap-2">
<span class="text-xs text-muted-foreground">Sort by:</span>
<BbNativeSelect TValue="string" Value="@("price")">
<option value="price">Price (low to high)</option>
<option value="duration">Duration (shortest)</option>
<option value="departure">Departure (earliest)</option>
</BbNativeSelect>
</div>
</div>
@* Flight Cards *@
@foreach (var flight in flights)
{
<BbCard Class="overflow-hidden">
<BbCardContent Class="p-4">
<div class="flex flex-col md:flex-row md:items-center gap-4">
@* Airline Info *@
<div class="flex items-center gap-3 md:w-36 shrink-0">
<BbAvatar Class="h-8 w-8 rounded-md shrink-0">
<BbAvatarFallback Class=@($"rounded-md text-[10px] font-bold text-white {flight.Color}")>@flight.AirlineCode</BbAvatarFallback>
</BbAvatar>
<div>
<p class="text-sm font-medium">@flight.Airline</p>
<p class="text-[10px] text-muted-foreground">@flight.FlightNo</p>
</div>
</div>
@* Route *@
<div class="flex-1 flex items-center gap-4">
<div class="text-center">
<p class="text-lg font-bold">@flight.DepartTime</p>
<p class="text-xs text-muted-foreground">@flight.Origin</p>
</div>
<div class="flex-1 flex flex-col items-center gap-0.5">
<span class="text-[10px] text-muted-foreground">@flight.Duration</span>
<div class="w-full flex items-center gap-1">
<div class="h-px flex-1 bg-border"></div>
<LucideIcon Name="plane" class="h-3 w-3 text-muted-foreground" />
<div class="h-px flex-1 bg-border"></div>
</div>
<BbBadge Variant="@(flight.Stops == "Non-stop" ? BadgeVariant.Default : BadgeVariant.Secondary)" Class="text-[10px] h-4 px-1.5">@flight.Stops</BbBadge>
</div>
<div class="text-center">
<p class="text-lg font-bold">@flight.ArriveTime</p>
<p class="text-xs text-muted-foreground">@flight.Destination</p>
</div>
</div>
@* Price + Action *@
<div class="flex flex-col items-end gap-2 md:w-32 shrink-0">
<div class="text-right">
<p class="text-xl font-bold text-primary">@flight.Price</p>
<p class="text-[10px] text-muted-foreground">per person</p>
</div>
<BbRating Value="@flight.Stars" Max="5" ReadOnly="true" Size="RatingSize.Small" />
<BbSplitButton Size="ButtonSize.Small">
<ChildContent>Select</ChildContent>
<DropdownContent>
<BbSplitButtonItem>View Details</BbSplitButtonItem>
<BbSplitButtonSeparator />
<BbSplitButtonItem>Share</BbSplitButtonItem>
</DropdownContent>
</BbSplitButton>
</div>
</div>
@* Expandable Details *@
<BbAccordion Type="AccordionType.Single" Collapsible="true" Class="mt-2">
<BbAccordionItem Value="details">
<BbAccordionTrigger Class="text-xs py-2">Flight Details</BbAccordionTrigger>
<BbAccordionContent>
<div class="grid gap-3 md:grid-cols-3 text-xs">
<div>
<p class="font-medium mb-1">Route</p>
<p class="text-muted-foreground">@flight.Origin → @flight.Destination</p>
<p class="text-muted-foreground">Aircraft: Boeing 737-800</p>
</div>
<div>
<p class="font-medium mb-1">Baggage</p>
<p class="text-muted-foreground">Carry-on: 7kg included</p>
<p class="text-muted-foreground">Checked: 23kg included</p>
</div>
<div>
<p class="font-medium mb-1">Fare Rules</p>
<p class="text-muted-foreground">Cancellation: Free within 24h</p>
<p class="text-muted-foreground">Changes: $50 fee applies</p>
</div>
</div>
</BbAccordionContent>
</BbAccordionItem>
</BbAccordion>
</BbCardContent>
</BbCard>
}
@* Pagination *@
<div class="flex justify-center pt-2">
<BbPagination>
<BbPaginationContent>
<BbPaginationItem>
<BbPaginationPrevious ShowText="false" />
</BbPaginationItem>
<BbPaginationItem>
<BbPaginationLink IsActive="true">1</BbPaginationLink>
</BbPaginationItem>
<BbPaginationItem>
<BbPaginationLink>2</BbPaginationLink>
</BbPaginationItem>
<BbPaginationItem>
<BbPaginationLink>3</BbPaginationLink>
</BbPaginationItem>
<BbPaginationItem>
<BbPaginationEllipsis />
</BbPaginationItem>
<BbPaginationItem>
<BbPaginationNext ShowText="false" />
</BbPaginationItem>
</BbPaginationContent>
</BbPagination>
</div>
</div>
</div>
<BbSeparator />
@* Destination Showcase *@
<div>
<h2 class="text-lg font-semibold mb-3">Popular Destinations</h2>
<div class="grid gap-4 md:grid-cols-3">
<BbCard Class="overflow-hidden group cursor-pointer">
<BbAspectRatio Ratio="16.0/9.0">
<div class="w-full h-full bg-gradient-to-br from-blue-400 to-blue-600 flex items-end p-4">
<div>
<p class="text-white font-bold text-lg">Tokyo</p>
<p class="text-white/80 text-sm">From $699</p>
</div>
</div>
</BbAspectRatio>
</BbCard>
<BbCard Class="overflow-hidden group cursor-pointer">
<BbAspectRatio Ratio="16.0/9.0">
<div class="w-full h-full bg-gradient-to-br from-orange-400 to-pink-500 flex items-end p-4">
<div>
<p class="text-white font-bold text-lg">Paris</p>
<p class="text-white/80 text-sm">From $449</p>
</div>
</div>
</BbAspectRatio>
</BbCard>
<BbCard Class="overflow-hidden group cursor-pointer">
<BbAspectRatio Ratio="16.0/9.0">
<div class="w-full h-full bg-gradient-to-br from-emerald-400 to-teal-500 flex items-end p-4">
<div>
<p class="text-white font-bold text-lg">Bali</p>
<p class="text-white/80 text-sm">From $549</p>
</div>
</div>
</BbAspectRatio>
</BbCard>
</div>
</div>
</div>
}
</div>
</div>
@code {
private string _activeTab = "flights";
private string? originValue;
private string? destValue;
private (double Start, double End) priceRange = (100, 1500);
private double durationHours = 16;
private decimal budget = 2000m;
private string ffNumber = "";
private TimeSpan? departureTime;
private IEnumerable<string>? selectedAirlines;
private record FlightInfo(string Airline, string AirlineCode, string FlightNo, string DepartTime, string ArriveTime, string Origin, string Destination, string Duration, string Stops, string Price, string Color, double Stars);
private readonly SelectOption<string>[] _airportOptions =
[
new("LAX", "LAX - Los Angeles"), new("JFK", "JFK - New York"), new("SFO", "SFO - San Francisco"),
new("ORD", "ORD - Chicago"), new("MIA", "MIA - Miami"), new("LHR", "LHR - London"),
new("CDG", "CDG - Paris"), new("NRT", "NRT - Tokyo"), new("DXB", "DXB - Dubai"),
new("SIN", "SIN - Singapore"), new("SYD", "SYD - Sydney"), new("HKG", "HKG - Hong Kong")
];
private readonly SelectOption<string>[] _airlineOptions = "United Airlines,Delta Air Lines,American Airlines,JetBlue,Southwest,British Airways,Air France,Emirates".Split(',').Select(SelectOption.FromValue).ToArray();
private List<FlightInfo> flights = new()
{
new("United Airlines", "UA", "UA 1234", "6:30 AM", "2:45 PM", "LAX", "JFK", "5h 15m", "Non-stop", "$328", "bg-blue-900", 4),
new("Delta Air Lines", "DL", "DL 890", "9:15 AM", "6:30 PM", "LAX", "JFK", "5h 15m", "Non-stop", "$356", "bg-red-700", 4),
new("JetBlue", "B6", "B6 421", "11:00 AM", "10:20 PM", "LAX", "JFK", "8h 20m", "1 stop", "$249", "bg-blue-600", 3),
};
}