@@ -69,6 +69,7 @@ type ComboboxContextValue = {
6969 contentId : string ;
7070 disabled ?: boolean ;
7171 locale : string ;
72+ modal : boolean ;
7273 onOpenChange ( open : boolean ) : void ;
7374 onTriggerChange ( node : ComboboxInputElement | null ) : void ;
7475 onValueChange ( value : string | undefined ) : void ;
@@ -106,6 +107,13 @@ interface RootProps {
106107 defaultTextValue ?: string ;
107108 disabled ?: boolean ;
108109 locale ?: string ;
110+ /**
111+ * The modality of the combobox. When set to `true`, interaction with
112+ * outside elements will be disabled and only the combobox content will
113+ * be visible to screen readers.
114+ * @default true
115+ */
116+ modal ?: boolean ;
109117 onOpenChange ?( open : boolean ) : void ;
110118 onValueChange ?( value : string ) : void ;
111119 onTextValueChange ?( textValue : string ) : void ;
@@ -177,6 +185,7 @@ const Combobox = (props: RootProps) => {
177185 disabled,
178186 required = false ,
179187 locale = 'en-EN' ,
188+ modal = true ,
180189 onTextValueChange,
181190 textValue : textValueProp ,
182191 defaultTextValue,
@@ -266,8 +275,8 @@ const Combobox = (props: RootProps) => {
266275
267276 // aria-hide everything except the content (better supported equivalent to setting aria-modal)
268277 React . useEffect ( ( ) => {
269- if ( content && trigger ) return hideOthers ( [ content , trigger ] ) ;
270- } , [ content , trigger ] ) ;
278+ if ( modal && content && trigger ) return hideOthers ( [ content , trigger ] ) ;
279+ } , [ modal , content , trigger ] ) ;
271280
272281 return (
273282 < ComboboxProviders >
@@ -284,6 +293,7 @@ const Combobox = (props: RootProps) => {
284293 onOpenChange = { setOpen }
285294 disabled = { disabled }
286295 locale = { locale }
296+ modal = { modal }
287297 focusFirst = { focusFirst }
288298 textValue = { textValue }
289299 onTextValueChange = { setTextValue }
@@ -330,7 +340,7 @@ const ComboboxTrigger = React.forwardRef<ComboboxTriggerElement, TriggerProps>((
330340 asChild
331341 // we make sure we're not trapping once it's been closed
332342 // (closed !== unmounted when animating out)
333- trapped = { context . open }
343+ trapped = { context . modal && context . open }
334344 onMountAutoFocus = { ( event ) => {
335345 // we prevent open autofocus because we manually focus the selected item
336346 event . preventDefault ( ) ;
@@ -858,41 +868,41 @@ const ComboboxContentImpl = React.forwardRef<ComboboxContentImplElement, Combobo
858868 } ;
859869 } , [ onOpenChange ] ) ;
860870
861- return (
862- < RemoveScroll allowPinchZoom >
863- < DismissableLayer
864- asChild
865- onEscapeKeyDown = { onEscapeKeyDown }
866- onPointerDownOutside = { onPointerDownOutside }
867- // When focus is trapped, a focusout event may still happen.
868- // We make sure we don't trigger our `onDismiss` in such case.
869- onFocusOutside = { ( event ) => {
870- event . preventDefault ( ) ;
871- } }
872- onDismiss = { ( ) => {
873- context . onOpenChange ( false ) ;
874- context . trigger ?. focus ( { preventScroll : true } ) ;
871+ const content = (
872+ < DismissableLayer
873+ asChild
874+ onEscapeKeyDown = { onEscapeKeyDown }
875+ onPointerDownOutside = { onPointerDownOutside }
876+ // When focus is trapped, a focusout event may still happen.
877+ // We make sure we don't trigger our `onDismiss` in such case.
878+ onFocusOutside = { ( event ) => {
879+ event . preventDefault ( ) ;
880+ } }
881+ onDismiss = { ( ) => {
882+ context . onOpenChange ( false ) ;
883+ context . trigger ?. focus ( { preventScroll : true } ) ;
884+ } }
885+ >
886+ < ComboboxPopperPosition
887+ role = "listbox"
888+ id = { context . contentId }
889+ data-state = { context . open ? 'open' : 'closed' }
890+ onContextMenu = { ( event ) => event . preventDefault ( ) }
891+ { ...contentProps }
892+ ref = { composedRefs }
893+ style = { {
894+ // flex layout so we can place the scroll buttons properly
895+ display : 'flex' ,
896+ flexDirection : 'column' ,
897+ // reset the outline by default as the content MAY get focused
898+ outline : 'none' ,
899+ ...contentProps . style ,
875900 } }
876- >
877- < ComboboxPopperPosition
878- role = "listbox"
879- id = { context . contentId }
880- data-state = { context . open ? 'open' : 'closed' }
881- onContextMenu = { ( event ) => event . preventDefault ( ) }
882- { ...contentProps }
883- ref = { composedRefs }
884- style = { {
885- // flex layout so we can place the scroll buttons properly
886- display : 'flex' ,
887- flexDirection : 'column' ,
888- // reset the outline by default as the content MAY get focused
889- outline : 'none' ,
890- ...contentProps . style ,
891- } }
892- />
893- </ DismissableLayer >
894- </ RemoveScroll >
901+ />
902+ </ DismissableLayer >
895903 ) ;
904+
905+ return context . modal ? < RemoveScroll allowPinchZoom > { content } </ RemoveScroll > : content ;
896906 } ,
897907) ;
898908
0 commit comments