Skip to content

Commit a5337fb

Browse files
authored
Merge pull request #75 from seanpdoyle/scroll-into-view
Use `Element.scrollIntoView`
2 parents 3fe250b + 6b9d754 commit a5337fb

File tree

2 files changed

+11
-16
lines changed

2 files changed

+11
-16
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ These settings are available:
9292
- `tabInsertsSuggestions: boolean = true` - Control whether the highlighted suggestion is inserted when <kbd>Tab</kbd> is pressed (<kbd>Enter</kbd> will always insert a suggestion regardless of this setting). When `true`, tab-navigation will be hijacked when open (which can have negative impacts on accessibility) but the combobox will more closely imitate a native IDE experience.
9393
- `defaultFirstOption: boolean = false` - If no options are selected and the user presses <kbd>Enter</kbd>, should the first item be inserted? If enabled, the default option can be selected and styled with `[data-combobox-option-default]` . This should be styled differently from the `aria-selected` option.
9494
> **Warning** Screen readers will not announce that the first item is the default. This should be announced explicitly with the use of `aria-live` status text.
95+
- `scrollIntoViewOptions?: boolean | ScrollIntoViewOptions = undefined` - When
96+
controlling the element marked `[aria-selected="true"]` with keyboard navigation, the selected element will be scrolled into the viewport by a call to [Element.scrollIntoView][]. Configure this value to control the scrolling behavior (either with a `boolean` or a [ScrollIntoViewOptions][] object.
97+
98+
[Element.scrollIntoView]: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
99+
[ScrollIntoViewOptions]: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#sect1
100+
95101

96102
## Development
97103

src/index.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export type ComboboxSettings = {
22
tabInsertsSuggestions?: boolean
33
defaultFirstOption?: boolean
4+
scrollIntoViewOptions?: boolean | ScrollIntoViewOptions
45
}
56

67
export default class Combobox {
@@ -13,16 +14,18 @@ export default class Combobox {
1314
ctrlBindings: boolean
1415
tabInsertsSuggestions: boolean
1516
defaultFirstOption: boolean
17+
scrollIntoViewOptions?: boolean | ScrollIntoViewOptions
1618

1719
constructor(
1820
input: HTMLTextAreaElement | HTMLInputElement,
1921
list: HTMLElement,
20-
{tabInsertsSuggestions, defaultFirstOption}: ComboboxSettings = {}
22+
{tabInsertsSuggestions, defaultFirstOption, scrollIntoViewOptions}: ComboboxSettings = {}
2123
) {
2224
this.input = input
2325
this.list = list
2426
this.tabInsertsSuggestions = tabInsertsSuggestions ?? true
2527
this.defaultFirstOption = defaultFirstOption ?? false
28+
this.scrollIntoViewOptions = scrollIntoViewOptions
2629

2730
this.isComposing = false
2831

@@ -108,7 +111,7 @@ export default class Combobox {
108111
this.input.setAttribute('aria-activedescendant', target.id)
109112
target.setAttribute('aria-selected', 'true')
110113
fireSelectEvent(target)
111-
scrollTo(this.list, target)
114+
target.scrollIntoView(this.scrollIntoViewOptions)
112115
} else {
113116
el.removeAttribute('aria-selected')
114117
}
@@ -209,17 +212,3 @@ function trackComposition(event: Event, combobox: Combobox): void {
209212

210213
combobox.clearSelection()
211214
}
212-
213-
function scrollTo(container: HTMLElement, target: HTMLElement) {
214-
if (!inViewport(container, target)) {
215-
container.scrollTop = target.offsetTop
216-
}
217-
}
218-
219-
function inViewport(container: HTMLElement, element: HTMLElement): boolean {
220-
const scrollTop = container.scrollTop
221-
const containerBottom = scrollTop + container.clientHeight
222-
const top = element.offsetTop
223-
const bottom = top + element.clientHeight
224-
return top >= scrollTop && bottom <= containerBottom
225-
}

0 commit comments

Comments
 (0)