@@ -32,10 +32,10 @@ implement the corresponding ARIA pattern. Every functionality needed should be
3232provided out-of-the-box: menu toggle, item selection and up/down movement
3333between them, screen reader support, focus management etc.
3434
35- ## Breaking Changes in v8
35+ ## Breaking Changes in v8 and v9
3636
37- _ useCombobox_ has been affected by breaking changes in v8, so check out the
38- [ migration page ] [ migration-guide-v8 ] .
37+ _ useCombobox_ has been affected by breaking changes in v8 and v9 , so check out
38+ the migration pages for v8 [ migration-guide-v8] and v9 [ migration-guide-v9 ] .
3939
4040## Breaking Changes in v7
4141
@@ -207,7 +207,7 @@ with the resulting DOM element, we don't need to do anything specific rather
207207than just spreading the getter props, apart from the case of the _ Input_ , which
208208renders a wrapper element over the actual HTML _ input_ . In this case, since
209209_ Input_ provides a prop for accessing the _ input_ element called _ inputRef_ , we
210- will use the getter function like this: _ getInputProps ({ refKey : ' inputRef' } )_ .
210+ will use the getter function like this: ` getInputProps ({refKey: 'inputRef'})` .
211211
212212Another point worth mentioning is that in this case items are objects and not
213213strings. As a result, the _ itemToString_ prop is passed to _ useCombobox_ . It
@@ -906,6 +906,152 @@ function ComboBoxExample() {
906906}
907907```
908908
909+ ## Multiple selection with Tag Group
910+
911+ ``` jsx live
912+ function TagGroupExample () {
913+ const books = [
914+ {id: ' book-1' , author: ' Harper Lee' , title: ' To Kill a Mockingbird' },
915+ {id: ' book-2' , author: ' Lev Tolstoy' , title: ' War and Peace' },
916+ {id: ' book-3' , author: ' Fyodor Dostoyevsy' , title: ' The Idiot' },
917+ {id: ' book-4' , author: ' Oscar Wilde' , title: ' A Picture of Dorian Gray' },
918+ {id: ' book-5' , author: ' George Orwell' , title: ' 1984' },
919+ {id: ' book-6' , author: ' Jane Austen' , title: ' Pride and Prejudice' },
920+ {id: ' book-7' , author: ' Marcus Aurelius' , title: ' Meditations' },
921+ {
922+ id: ' book-8' ,
923+ author: ' Fyodor Dostoevsky' ,
924+ title: ' The Brothers Karamazov' ,
925+ },
926+ {id: ' book-9' , author: ' Lev Tolstoy' , title: ' Anna Karenina' },
927+ {id: ' book-10' , author: ' Fyodor Dostoevsky' , title: ' Crime and Punishment' },
928+ ]
929+
930+ function TagGroup () {
931+ const initialItems = books .slice (0 , 2 )
932+ const [inputValue , setInputValue ] = React .useState (' ' )
933+
934+ const {
935+ addItem ,
936+ getTagProps ,
937+ getTagRemoveProps ,
938+ getTagGroupProps ,
939+ items ,
940+ activeIndex ,
941+ } = useTagGroup ({
942+ initialItems,
943+ })
944+ const itemsToAdd = books .filter (
945+ book =>
946+ ! items .includes (book) &&
947+ (! inputValue ||
948+ book .title .toLowerCase ().includes (inputValue .toLowerCase ()) ||
949+ book .author .toLowerCase ().includes (inputValue .toLowerCase ())),
950+ )
951+ const {
952+ isOpen ,
953+ getToggleButtonProps ,
954+ getLabelProps ,
955+ getMenuProps ,
956+ getInputProps ,
957+ highlightedIndex ,
958+ getItemProps ,
959+ } = useCombobox ({
960+ items: itemsToAdd,
961+ inputValue,
962+ onInputValueChange : ({inputValue}) => {
963+ setInputValue (inputValue)
964+ },
965+ onSelectedItemChange ({selectedItem}) {
966+ if (selectedItem) {
967+ addItem (selectedItem)
968+ }
969+ },
970+ selectedItem: null ,
971+ stateReducer (_state , actionAndChanges ) {
972+ const {changes } = actionAndChanges
973+
974+ if (changes .selectedItem ) {
975+ return {... changes, inputValue: ' ' , highlightedIndex: 0 , isOpen: true }
976+ }
977+
978+ return changes
979+ },
980+ })
981+
982+ return (
983+ < div>
984+ < div
985+ {... getTagGroupProps ({' aria-label' : ' books usage example' })}
986+ className= " inline-flex gap-2 items-center flex-wrap p-1.5"
987+ >
988+ {items .map ((item , index ) => (
989+ < span
990+ className= {` ${
991+ index === activeIndex ? ' italic' : ' '
992+ } "border border-green-800 bg-green-600 px-1.5 mx-0.5 rounded-[10px] cursor-default hover:opacity-50 focus:bg-red-600 focus:border-red-800"` }
993+ key= {item .id }
994+ {... getTagProps ({index, ' aria-label' : item .title })}
995+ >
996+ {item .title }
997+ < span
998+ className= " p-1 cursor-pointer border-0 bg-transparent"
999+ {... getTagRemoveProps ({index, ' aria-label' : ' remove' })}
1000+ >
1001+ & #10005 ;
1002+ < / span>
1003+ < / span>
1004+ ))}
1005+ < / div>
1006+ < div className= " w-72 flex flex-col gap-1" >
1007+ < label className= " w-fit" {... getLabelProps ()}>
1008+ Choose your favorite book:
1009+ < / label>
1010+ < div className= " flex shadow-sm bg-white gap-0.5" >
1011+ < input
1012+ placeholder= " Best book ever"
1013+ className= " w-full p-1.5"
1014+ {... getInputProps ()}
1015+ / >
1016+ < button
1017+ aria- label= " toggle menu"
1018+ className= " px-2"
1019+ type= " button"
1020+ {... getToggleButtonProps ()}
1021+ >
1022+ {isOpen ? <> & #8593 ;< / > : <> & #8595 ;< / > }
1023+ < / button>
1024+ < / div>
1025+ < / div>
1026+ < ul
1027+ className= {` absolute w-72 bg-white mt-1 shadow-md max-h-80 overflow-scroll p-0 z-10 ${
1028+ ! (isOpen && itemsToAdd .length ) && ' hidden'
1029+ } ` }
1030+ {... getMenuProps ()}
1031+ >
1032+ {isOpen &&
1033+ itemsToAdd .map ((item , index ) => (
1034+ < li
1035+ className= {cx (
1036+ highlightedIndex === index && ' bg-blue-300' ,
1037+ ' py-2 px-3 shadow-sm flex flex-col' ,
1038+ )}
1039+ key= {item .id }
1040+ {... getItemProps ({item, index})}
1041+ >
1042+ < span> {item .title }< / span>
1043+ < span className= " text-sm text-gray-700" > {item .author }< / span>
1044+ < / li>
1045+ ))}
1046+ < / ul>
1047+ < / div>
1048+ )
1049+ }
1050+
1051+ return < TagGroup / >
1052+ }
1053+ ```
1054+
9091055## Using action props
9101056
9111057Action props are functions returned by _ useCombobox_ along with the state props
@@ -1207,3 +1353,5 @@ repository][examples-code-sandbox].
12071353 https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V7.md#usecombobox
12081354[ migration-guide-v8] :
12091355 https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V8.md
1356+ [ migration-guide-v9] :
1357+ https://github.com/downshift-js/downshift/tree/master/src/hooks/MIGRATION_V9.md
0 commit comments