Finder
Use static rules to effortlessly sort, filter, search, and group data of any shape.
Objects, classes, strings; whatever dataset you're manipulating, you can use a Rule to connect Finder to manipulate it. You don't need to transform your object to match an external rubric.
Reusable
Rules are object literals that can create reusable searches, filters, sorting, or grouping. Write a Rule once, use it everywhere you're working with that object - catalog, customer orders, monthly dashboards and so on!
Effortless string matching
Extract a string ( or strings ) from your item to search against. Rank searches by closest match to return relevant results faster. The <Finder.SearchTermHaystack /> component will highlight the matching segments of your Item's search term.
Coupled Rules
If you have rules that need to interact with each other, you can add ruleEffects to listen for rule changes. If certain filters are mutually incompatible, or you need to reset the sortBy rules when the active groupBy rule changes, ruleEffects will get it done.
Headless
Finder provides an API for managing rules and displaying matches. It doesn't have any opinions on how matches or controls should be rendered.
Rule Examples
- Search shoes
- Filter birds
- Sort fruits
- Group cars
interface Shoe {
product {
name: string;
};
image: string;
}
const rule = searchRule<Shoe>({
searchFn: (item) => item.product.name
});
return <Finder items={shoes} rules={[rule]} />
Find that perfect shoe
interface Avian {
name: string;
territory: string;
}
const rule = filterRule<Avian>({
id: 'territory_filter',
filterFn: (birb, value) => birb.territory === value;
})
return <Finder items={birds} rules={[rule]} />
Filter Fowl
Habitat: Yukon
Habitat: Yukon
Habitat: Prince Edward Island
Habitat: Northwest Territories
Habitat: Manitoba
Habitat: Manitoba
Habitat: Nova Scotia
Habitat: New Brunswick
Habitat: Manitoba
Habitat: Saskatchewan
Habitat: Nova Scotia
Habitat: Alberta
Habitat: Nunavut
Habitat: Newfoundland and Labrador
Habitat: Ontario
Habitat: Prince Edward Island
Habitat: Alberta
Habitat: Newfoundland and Labrador
Habitat: Yukon
Habitat: Quebec
Habitat: Ontario
Habitat: Saskatchewan
Habitat: Saskatchewan
Habitat: Northwest Territories
Habitat: British Columbia
Habitat: Saskatchewan
Habitat: Northwest Territories
Habitat: New Brunswick
Habitat: Saskatchewan
Habitat: Nunavut
Habitat: Nunavut
Habitat: Manitoba
Habitat: Nunavut
Habitat: Newfoundland and Labrador
Habitat: Quebec
Habitat: Alberta
Habitat: Quebec
Habitat: Yukon
Habitat: Prince Edward Island
Habitat: British Columbia
Habitat: Nunavut
Habitat: British Columbia
Habitat: Nova Scotia
Habitat: Alberta
Habitat: New Brunswick
Habitat: Manitoba
Habitat: Northwest Territories
Habitat: Ontario
Habitat: Nova Scotia
Habitat: Nova Scotia
Habitat: Alberta
Habitat: Quebec
Habitat: Manitoba
Habitat: Prince Edward Island
Habitat: Manitoba
Habitat: Manitoba
Habitat: Prince Edward Island
Habitat: Nunavut
Habitat: Saskatchewan
Habitat: Quebec
Habitat: Quebec
Habitat: Nunavut
Habitat: Quebec
Habitat: British Columbia
Habitat: Nova Scotia
Habitat: Newfoundland and Labrador
Habitat: Newfoundland and Labrador
Habitat: Quebec
Habitat: Manitoba
Habitat: British Columbia
Habitat: Manitoba
Habitat: Prince Edward Island
Habitat: Alberta
Habitat: Yukon
Habitat: New Brunswick
Habitat: Saskatchewan
Habitat: Prince Edward Island
Habitat: Northwest Territories
Habitat: Nova Scotia
Habitat: Newfoundland and Labrador
Habitat: Prince Edward Island
Habitat: British Columbia
Habitat: Northwest Territories
Habitat: Prince Edward Island
Habitat: Prince Edward Island
Habitat: Nunavut
Habitat: British Columbia
Habitat: Nova Scotia
Habitat: British Columbia
Habitat: Newfoundland and Labrador
Habitat: Nova Scotia
Habitat: British Columbia
Habitat: Saskatchewan
Habitat: Northwest Territories
Habitat: New Brunswick
Habitat: Saskatchewan
Habitat: Newfoundland and Labrador
Habitat: Nunavut
Habitat: Alberta
Habitat: Nova Scotia
interface Fruit {
name: string;
price: number;
expiry_date: Date;
}
const ruleset = finderRuleset<Fruit>([
sortByRule({
id: 'expiry_date',
sortFn: (fruit) => fruit.expiry_date.getTime(),
label: "Expires soon",
defaultSortDirection: 'desc'
}),
sortByRule({
id: 'price',
sortFn: (fruit) => fruit.price,
label: "Price lowest to highest"
}
]));
return <Finder items={fruits} rules={ruleset} />
Ye Olde Banana Stand
Expires: Wed, May 27
Expires: Wed, May 27
Expires: Thu, May 28
Expires: Fri, May 29
Expires: Fri, May 29
Expires: Fri, May 29
Expires: Fri, May 29
Expires: Sat, May 30
Expires: Sun, May 31
Expires: Sun, May 31
Expires: Sun, May 31
Expires: Sun, May 31
Expires: Sun, May 31
Expires: Mon, Jun 1
Expires: Mon, Jun 1
Expires: Mon, Jun 1
Expires: Tue, Jun 2
Expires: Wed, Jun 3
Expires: Thu, Jun 4
Expires: Thu, Jun 4
Expires: Thu, Jun 4
Expires: Fri, Jun 5
Expires: Fri, Jun 5
Expires: Sat, Jun 6
Expires: Sat, Jun 6
Expires: Sat, Jun 6
Expires: Sat, Jun 6
Expires: Sun, Jun 7
Expires: Sun, Jun 7
Expires: Sun, Jun 7
Expires: Sun, Jun 7
Expires: Mon, Jun 8
Expires: Tue, Jun 9
Expires: Tue, Jun 9
Expires: Tue, Jun 9
Expires: Tue, Jun 9
Expires: Tue, Jun 9
Expires: Tue, Jun 9
Expires: Thu, Jun 11
Expires: Thu, Jun 11
Expires: Thu, Jun 11
Expires: Fri, Jun 12
Expires: Fri, Jun 12
Expires: Sat, Jun 13
Expires: Sat, Jun 13
Expires: Sat, Jun 13
Expires: Sat, Jun 13
Expires: Sun, Jun 14
Expires: Sun, Jun 14
Expires: Mon, Jun 15
Expires: Mon, Jun 15
Expires: Mon, Jun 15
Expires: Mon, Jun 15
Expires: Tue, Jun 16
Expires: Tue, Jun 16
Expires: Tue, Jun 16
Expires: Tue, Jun 16
Expires: Wed, Jun 17
Expires: Wed, Jun 17
Expires: Wed, Jun 17
Expires: Wed, Jun 17
Expires: Thu, Jun 18
Expires: Thu, Jun 18
Expires: Fri, Jun 19
Expires: Fri, Jun 19
Expires: Fri, Jun 19
Expires: Fri, Jun 19
Expires: Fri, Jun 19
Expires: Sat, Jun 20
Expires: Sun, Jun 21
Expires: Sun, Jun 21
Expires: Sun, Jun 21
Expires: Sun, Jun 21
Expires: Sun, Jun 21
Expires: Sun, Jun 21
Expires: Mon, Jun 22
Expires: Mon, Jun 22
Expires: Mon, Jun 22
Expires: Mon, Jun 22
Expires: Tue, Jun 23
Expires: Tue, Jun 23
Expires: Tue, Jun 23
Expires: Wed, Jun 24
Expires: Thu, Jun 25
Expires: Thu, Jun 25
Expires: Fri, Jun 26
Expires: Fri, Jun 26
Expires: Sat, Jun 27
Expires: Sat, Jun 27
Expires: Sun, Jun 28
Expires: Sun, Jun 28
Expires: Sun, Jun 28
Expires: Sun, Jun 28
Expires: Mon, Jun 29
Expires: Mon, Jun 29
Expires: Mon, Jun 29
Expires: Tue, Jun 30
Expires: Wed, Jul 1
Expires: Wed, Jul 1
Expires: Thu, Jul 2
interface Vehicle {
name: string;
make: string;
model: string;
melts_in_rain: boolean;
}
const rule = groupByRule<Vehicle>({
id: 'group_by_make',
groupFn: (car) => car.make,
label: "Make",
// want to sticky certain groups to the top or bottom of the list?
// Use the sticky prop to weight them.
sticky: {
header: ['Honda'],
footer: 'Tesla'
}
})
return <Finder items={vehicles} rules={[rule]} requireGroup={true} />
Groupable Cars
Honda (2)
Violet
Sky blue
Ford (3)
Lavender
Grey
Gold
Aston Martin (3)
Plum
Fuchsia
Fuchsia
Audi (3)
Orchid
Indigo
Silver
BYD (1)
Lime
Bentley (3)
Pink
Turquoise
Maroon
Bugatti (3)
Orchid
Sky blue
Maroon
Chrysler (3)
Tan
White
Yellow
Citroën (1)
Salmon
Dodge (4)
Lavender
Lime
Fuchsia
Magenta
Ferrari (2)
Orchid
Maroon
Fiat (7)
Azure
Azure
White
Grey
Blue
Azure
Green
Hyundai (1)
Blue
Jaguar (4)
Black
Red
Blue
Purple
Jeep (1)
Violet
Kia (2)
Maroon
Magenta
Land Rover (2)
Yellow
Red
Mahindra & Mahindra (6)
Orchid
Lavender
Turquoise
Sky blue
Salmon
Blue
Maruti (1)
Cyan
Maserati (3)
Cyan
Maroon
Ivory
Mazda (1)
Cyan
Mercedes Benz (1)
Ivory
Mini (4)
Sky blue
Azure
Olive
Fuchsia
Mitsubishi (4)
Sky blue
Lavender
Red
Indigo
NIO (1)
Orchid
Nissan (2)
Purple
Violet
Peugeot (3)
Gold
Maroon
Turquoise
Polestar (3)
Olive
Red
Magenta
Porsche (3)
Azure
Green
Teal
Rivian (2)
Mint green
Pink
Rolls Royce (2)
Mint green
Plum
Skoda (1)
Plum
Smart (4)
Tan
Maroon
Azure
Teal
Suzuki (3)
Teal
Mint green
Cyan
Tata (1)
Salmon
Toyota (1)
Plum
Vauxhall (5)
Orchid
Indigo
Ivory
Mint green
Mint green
Volkswagen (4)
Lime
Purple
Violet
Maroon
Filtering and sorting data is the easiest thing in the world, and a disproportionate percentage of webdev tasks. It can also be a disproportionate amount of frustrations as client needs change at the last minute, filters get nested and coupled, and object shape changes.
Without good discipline and planning, data manipulation can become a spaghetti mountain of boilerplate. Finder is intended to make data manipulation easy, type-safe, and reusable.