Blacklight 9.0.0 includes changes from nearly 300 pull requests from 20 contributors made over 14 months (Sep 2024 - Nov 2025).
Highlights
- Dependencies. Drops support for older versions of major dependencies that may have still been supported in Blacklight 8. Notable new minimum versions: Rails 7.2+, Ruby 3.2+, Bootstrap 5.3+, ViewComponent 3.0+.
- JS/CSS Assets. Improves asset management by allowing Blacklight to be used and customized without Sass compilation. Most Sass variables have been converted to native CSS custom properties.
- Facets. Many improvements to facets, including more seams for customization/configuration, enhancements to the facet suggest/filtering feature, better accessibility & styling.
- Bookmarks. Improves bookmark icon usage, keyboard navigation, and event handling.
- Advanced Search. Improves and simplifies the native out-of-the-box Advanced Search functionality.
- Other UI & Accessibility Changes. Numerous enhancements including better skip links, more accessible use of ARIA roles, fixes to modals, constraints section and modal improvements.
Upgrading to Blacklight 9
An upgrade guide is available on the wiki.
https://github.com/projectblacklight/blacklight/wiki/Upgrading-to-Blacklight-9
What's Changed
PRs grouped by category, sorted by merge date, Sep 2024 - Nov 2025.
Facets
- Add a way to filter facets in the facets "more" modal by @sandbergja in #3367
- Provide a focus ring on facet open/close button by @jcoyne in #3378
- Remove role=treeitem by @jcoyne in #3359
- Remove undesirable class by @jcoyne in #3388
- Set facet_group_component in the config by @jcoyne in #3391
- Use Bootstrap 5 Accordion for the facet list by @jcoyne in #3262
- Create correct css class in stylesheet by @jcoyne in #3405
- Create a custom css class for the facet toggle button by @jcoyne in #3407
- Remove styles that add unnecessary border around collapsed facets. by @jcoyne in #3387
- Extract a FacetCollapseToggleButton component by @jcoyne in #3409
- Handle beginless/endless ranges in facet value by @taylor-steve in #3213
- Make modal facet "more" pagination controls be on either side of screen by @jrochkind in #3445
- Remove unnecessary css that pushes pagination out of alignment by @jcoyne in #3439
- Make the remove button hover color settable by css variable by @jcoyne in #3449
- Make text indent and left padding of facet values variables by @jcoyne in #3468
- Put the facet heading padding in a variable by @jcoyne in #3471
- Allowing styling for numerical and A-Z sort buttons to be passed into the FacetFieldPaginationComponent by @hudajkhan in #3492
- Strip markup from html_safe selected facet values in the html title. by @seanaery in #3464
- Ensure that facet suggestions are relevant to the user's query by @sandbergja in #3495
- Strip out new facet-only request keys by @maxkadel in #3509
- Forward-port improvements to the facet suggest feature by @sandbergja in #3511
- Fix typo on aria-controls attribute in FacetFieldComponent. by @seanaery in #3516
- [#3512] Support facebook-style query params in cases where a facet pivot is configured by @sandbergja in #3514
- Add some bottom margin to the facet-suggest filter in the modal. Clos… by @seanaery in #3525
- Fix facet prev/next nav link appearance when the link is disabled. Fi… by @seanaery in #3533
- Bugfix: allow facet filter/suggest input to work with the sort toggle… by @seanaery in #3538
- Fix wrapping for A-Z facet nav. Fixes #3523; relates to #2072. by @seanaery in #3539
- Fix facet prev/next pagination nav display within and outside of moda… by @seanaery in #3548
- Ensure facet filter gray box (in modal or facet browse page) doesn't … by @seanaery in #3553
- Remove unnecessary !important CSS rule. Followup for #3552. by @seanaery in #3567
- Permit markup on prev/next facet pagination buttons by @jcoyne in #3591
- Remove unused erb file by @jcoyne in #3615
- Get rid of unnecessary _facet_pagination template by @jcoyne in #3613
- Simplify FacetSuggestInput by only passing the presenter argument by @jcoyne in #3608
- Allow setting classes on FacetGroupComponent by @jcoyne in #3621
- Rename FacetSuggestInput to Facts::SuggestComponent by @jcoyne in #3611
- Extract variable for block-padding on facet values by @jcoyne in #3594
- Extract Facets::FiltersComponent so it's display can be customized by @jcoyne in #3609
- Add more explanation about index_range configuration by @jcoyne in #3607
- Move facet components to Facets namespace by @jcoyne in #3614
- Extract FilterQueryBuilder to its own class by @jcoyne in #3599
- Extract selected facet value component by @jcoyne in #3610
- Drop backward compatibility path by @jcoyne in #3616
- Remove unnecessary partial and move render conditions to component by @jcoyne in #3605
- The JSON presenter should use all facets by @jcoyne in #3649
- Make Facets::FiltersComponent configurable by @jcoyne in #3654
- Allow components to be passed into facets/filters_component by @jcoyne in #3655
- Avoid DeprecatedConstantProxy for classes by @jcoyne in #3642
- Allow classes to be configured on FacetGroupComponent by @jcoyne in #3658
- Allow the layout component to be overriden in a subclass by @jcoyne in #3648
- Remove facet_pivot partial as it is no longer used. by @seanaery in #3670
- Fix pivot facet accessibility by using tree, treeitem aria roles. Fix… by @seanaery in #3671
- Fix color contrast accessibility in facet headers. Fixes #3560. by @seanaery in #3666
- Fix pivot facet alignment and expander styles; improve example pivot config. Fixes #3554 & #3679. by @seanaery in #3680
- Commit the compiled blacklight.css file from #3680 pivot facet style … by @seanaery in #3682
- Create facet item presenter instances via the facet presenter by @jcoyne in #3688
- Add documentation to FacetItemPresenter by @jcoyne in #3687
- Remove unnecessary method facet_value_for_facet_item by @jcoyne in #3689
- Add documentation to Facets::ItemComponent by @jcoyne in #3692
- Add documentation to FacetItemPivotComponent by @jcoyne in #3691
- Fix facet suggest catalog path by @mksndz in #3711
- 3727 link to facet renders html for non html formats by @mamrey in #3728
- Add a note about the suggest configuration option for facets by @sandbergja in #3759
- Add a blacklight_config.default_facet_suggest, to allow turn off new facet suggest feature by default by @jrochkind in #3760
- Redesign facet suggest input styling/layout by @jrochkind in #3769
- Switch facet suggest request to have query in URL query params, instead of path, with proper escaping by @jrochkind in #3774
Constraints
- Use icon instead of a carat character by @jcoyne in #3401
- Remove start over partial by @jcoyne in #3328
- Set constraints_component in the config by @jcoyne in #3392
- Set the max-width of constraints with clamp() by @jcoyne in #3433
- Remove hover style from non-controllable element by @jcoyne in #3470
- The fs-4 class has no effect on an svg by @jcoyne in #3644
- Avoid transforming the size of the icon by @jcoyne in #3645
- Use a larger Bootstrap close icon for constraint removal. Fixes #3660. by @seanaery in #3661
- Extract remove_button method for easier customization of the applied … by @jcoyne in #3662
- Create methods for ConstraintComponent by @jcoyne in #3686
- Extract a special purpose ConstraintPresenter by @jcoyne in #3690
- Move start-over button to end of constraints by @body-clock in #3703
- 3701 visually show you searched for and remove constraints heading by @body-clock in #3704
Bookmarks
- Disambiguate .toggle-bookmark by @jcoyne in #3306
- Change bookmarkCounter to find multiple selectors by @kirkkwang in #3351
- Bookmark counter spec by @mamrey in #3263
- Switch to using the bookmark icon by default by @jcoyne in #3389
- Create a blacklight specific variable for the bookmark icon color by @jcoyne in #3490
- Retain keyboard focus on bookmark checkbox by @paulhagon in #3602
- Compare document with bookmark using string compairson of class by @jcoyne in #3593
- add bookmarks keyboard navigation listener by @dnoneill in #3646
- add blacklight event for bookmarks by @dnoneill in #3659
- fix custom event detail by @dnoneill in #3665
- Extract methods for overriding bookmark response by @jcoyne in #3667
- Add bookmark-counter class and update bootstrap 5 classes by @jcoyne in #3669
- BookmarkComponent is no longer an ancestor of ActionComponent by @jcoyne in #3668
- set the bookmark event on form instead of window by @dnoneill in #3693
Modals
- Restore modal events that were dropped in Blacklight 8 by @cbeer in #3408
- isDefaultPrevented was a jquery-ism. by @cbeer in #3411
- Fix scrolling of longer-than-viewport bootstrap modal in a by @jrochkind in #3447
- Let a click on backdrop behind modal close the modal by @jrochkind in #3452
- When modal is open, turn off body scrolling by @jrochkind in #3453
- Import and export modalForm.js so it is included in the rollup build by @sandbergja in #3467
- Darken modal backdrops, to match Bootstrap opacity. Fixes #3561. by @seanaery in #3562
- Remove unused modalForm by @jcoyne in #3581
- Remove unused variable by @jcoyne in #3590
- Set requested with header on fetch request by @jcoyne in #3672
- Restore scrolling and execute other modal hide behavior on modal dismiss by "escape" key by @jrochkind in #3694
- Allow modalSetup to be called when no modal DOM is on page by @jrochkind in #3724
Advanced Search
- Use SearchBuilder in AdvancedSearchFormComponent spec by @jcoyne in #3637
- Ensure facets on advanced search form styles are consistent with side… by @seanaery in #3674
- Make the built-in advanced search work correctly out-of-the-box for a… by @seanaery in #3742
- Resolve "Refine display of constraints in advanced search form" by @mamrey in #3751
- Advance search facets by @jcoyne in #3767
Other UI & Accessibility Changes
- moves next after numbers by @dnoneill in #3272
- Show the item page information even if there's only one result by @cbeer in #3381
- Swap order of skip links so main content comes first by @thatbudakguy in #3354
- update link_to_search to work with only one/no search_field by @dnoneill in #3422
- Use a labeled for show tools sidebar by @thatbudakguy in #3423
- Remove unnecessary role. The role is implied by the main HTML element by @jcoyne in #3393
- Remove icons should be aria-hidden by @jcoyne in #3399
- Remove redundant aria role from nav element by @corylown in #3457
- add aria-current for view-type buttons by @dnoneill in #3465
- Update skip links style by @jcoyne in #3461
- Ensure that the search bar is visible when focused via anchor link by @thatbudakguy in #3505
- [#3518] Remove incomplete implementation of menu aria role from Blacklight::System::DropdownComponent by @sandbergja in #3519
- Permit markup on prev/next session context buttons by @jcoyne in #3583
- Only render the flash message partial when there are messages to show… by @seanaery in #3684
- Resolve '3739 render multiple dd elements for multivalued fields' by @mamrey in #3743
Bootstrap
- Remove bootstrap 4 support by @jcoyne in #3226
- Explictly add the form-control class to the auto-complete by @jcoyne in #3205
- Explicitly set the margin class on the constraint component by @jcoyne in #3204
- Don't install the bootstrap gem unless they are using sassc by @jcoyne in #3363
- Apply bootstrap style to title with classes instead of sass extend by @jcoyne in #3199
- Remove breakpoint specific visually hidden styles by @jcoyne in #3375
- Extract styles applied at all breakpoints by @jcoyne in #3379
- Remove obsolete bootstrap function call by @jcoyne in #3377
- Remove unnecessary styles by @jcoyne in #3383
- Remove non-existing class navbar-toggler-right by @jcoyne in #3406
- Prefer bootstrap classes to custom classes for margins by @jcoyne in #3413
- Directly use the visually-hidden class by @jcoyne in #3373
- Set sort-widget-padding with explicit bootstrap classes rather than CSS by @jcoyne in #3416
- Add bootstrap class to float-right rather than requiring custom css by @jcoyne in #3429
- Use bootstrap classes to apply margin by @jcoyne in #3434
- Set search bar border rounded class for number of configured search fields by @corylown in #3450
- Upgrade bootstrap to 5.3.5 by @jcoyne in #3565
- Drop jumbotron classes by @jcoyne in #3603
- Remove deprecated navbar-dark class by @jcoyne in #3604
- Add margin bottom Bootstrap class to Search/Paginate by @body-clock in #3623
- Update bootstrap dependency in package.lock by @jcoyne in #3620
- Remove vestiges of bootstrap 4 close by @jcoyne in #3657
- Remove all remaining vestiges of Bootstrap 3 & 4 classes/attributes. Resolves #3675 by @seanaery in #3676
- Remove comments that imply Bootstrap 4 is still supported in BL9 (it … by @seanaery in #3776
JS/CSS Assets & Asset Pipeline
- Remove rails-ujs by @jcoyne in #3225
- Rename 'Blacklight' inside of core.js as 'Core' by @jrochkind in #3355
- Precompile assets for propshaft by @jcoyne in #3365
- Test with esbuild/propshaft including both Rails 7.2 and 8.0 by @jrochkind in #3360
- Add the h4/h6 class to the facet headings rather than using scss by @jcoyne in #3201
- Upgrade rollup to v4 by @jcoyne in #3353
- Remove extend of .show by @jcoyne in #3374
- Avoid using deprecated sass darken method by @jcoyne in #3382
- unify importmap and npm use on 'blacklight-frontend', modernize package.json with exports by @jrochkind in #3371
- Use css variables for sort-pagination by @jcoyne in #3417
- Use --bs-border-color rather than -border-color for document separator by @jcoyne in #3418
- Prune away unused CSS by @jcoyne in #3430
- Remove custom autocomplete styles by @jcoyne in #3410
- Switch to logical alignment by @jcoyne in #3436
- Remove unnecessary CSS rule by @jcoyne in #3435
- Use propshaft compatible url for logo image by @jcoyne in #3370
- Allow managing all settings from blacklight_defaults.scss via CSS variables by @jcoyne in #3438
- Enable building css so that you can run blacklight without sass by @jcoyne in #3184
- Rebuild the css file by @jcoyne in #3479
- Remove unused asset generator by @jcoyne in #3380
- Precompile assets in the host app before running specs by @jcoyne in #3362
- Fix importmap generator so it loads blacklight css using @import rath… by @seanaery in #3551
- Fix importmap generator order for blacklight & bootstrap CSS so black… by @seanaery in #3566
- Remove css that is not applied by @jcoyne in #3612
ViewComponent & View Refactoring
- Drop support for view_component 2 by @jcoyne in #3230
- Override ViewComponent::Base#sidecar_files instead of the compiler. by @cbeer in #3346
- Remove catalog/_search_form.html.erb by @jcoyne in #3332
- Remove deprecated show tools partial by @jcoyne in #3321
- Allow SearchBarComponent to set necessary classes by @jcoyne in #3197
- Remove the catalog/_constraints.html.erb partial by @jcoyne in #3331
- Explicitly pass classes on the search widgets by @jcoyne in #3203
- Explicitly set margin classes by @jcoyne in #3196
- Remove show_sidebar partial and helper by @jcoyne in #3334
- Remove deprecated _facets partial by @jcoyne in #3329
- Fix group rendering collection by @cbeer in #3402
- Remove catalog scope from grouped search results. by @cbeer in #3404
- Remove default partial slot value. by @cbeer in #3419
- Remove search_header partial by @jcoyne in #3395
- Remove header_navbar partial by @jcoyne in #3394
- Assert that view_config will be not nil by @jcoyne in #3344
- Extract a SkipLinkItemComponent by @jcoyne in #3478
- Modernized view component testing by @jcoyne in #3606
- Remove unused attribute by @jcoyne in #3617
- Stop passing both presenter and document around by @jcoyne in #3588
- Move logic out of thumbnail component template and into the class by @jcoyne in #3639
- Deprecate the
@documentinstance variable by @jcoyne in #3643 - Add accessors to DocumentComponent and use them by @jcoyne in #3650
- Pass no arguments to the superclass by @jcoyne in #3707
- Avoid ViewComponent::Base#set_slot by @jcoyne in #3708
- Decouple presenter specs from view_component by @jcoyne in #3709
- Add documentation about the sidecar_files method by @jcoyne in #3712
- Simplify DocumentComponent collection parameter by @jcoyne in #3714
- Further simplify DocumentComponent collection parameter by @jcoyne in #3716
- Update to view_component 4.0 by @jcoyne in #3706
- Remove unused positional arguments from component lambdas by @jcoyne in #3710
- Remove unsupported sitelinks searchbox by @mamrey in #3719
- Explicitly require
view_component/versionbefore trying to use it. by @cbeer in #3729 - Push default document components into the configuration. by @cbeer in #3733
- Push the default id for the show page back to the partial. by @cbeer in #3732
- Push presenter configuration up to the configuration by @cbeer in #3736
- Extract a partial local for presenter by @cbeer in #3735
Solr, SearchBuilder, & Search Result Retrieval
- Use SOLR_MODULES envvar, rather than solrconfig entries for Solr 9.8 compatibility by @sandbergja in #3497
- Use SOLR_MODULES in solr_wrapper config for Solr 9.8 compatibility by @cjcolvar in #3626
- Check for present query when appending boolean params by @body-clock in #3463
- Use the repository configured in blacklight.yml by @jcoyne in #3526
- Use the kwargs for search by @jcoyne in #3537
- Allow use of request builder by @jcoyne in #3536
- Remove active_fedora_model_ssi from solrconfig by @jcoyne in #3544
- Extract FacetSearchBuilder by @jcoyne in #3597
- Remove user_params argument from SearchService by @jcoyne in #3596
- Refactor test for Solr::Response by @jcoyne in #3630
- Refactor test to use SearchBuilder by @jcoyne in #3631
- Refactor Solr::Response::Group spec to use SearchBuider by @jcoyne in #3636
- Refactor Solr::Response::Facets spec to run with a SearchBuilder by @jcoyne in #3634
- Remove legacy document_solr_request_handler by @jcoyne in #3635
- Allow the repository class to be configured on a per-class basiss by @jcoyne in #3651
- Move tests for timeouts to the Solr::Repository spec by @jcoyne in #3547
- Add comments to SearchState#filters by @jcoyne in #3683
- Provide a way for applications to customize search result retrieval by @jcoyne in #3685
- solr_wrapper dir argument is best to parent dir including 'conf' by @jrochkind in #3697
- Extract a search_builder for a find one search by @jcoyne in #3633
- Allow Blacklight::Solr::Repository#search to be called with no args by @jrochkind in #3758
- Remove unused methods by @jcoyne in #3766
- Revert "Remove unused methods" by @jcoyne in #3768
- Remove unreachable code by @jcoyne in #3628
- Revert "Extract FacetSearchBuilder" by @jrochkind in #3762
Rails & Ruby Dependencies
- Generate Docker image with Rails 7.2, Ruby 3.3 and view_component 3.14 by @jcoyne in #3320
- Stop supporting Rails 6 by @jcoyne in #3224
- Bump rspec-rails dependency. by @cbeer in #3324
- Test on Rails 8 by @jcoyne in #3340
- Remove vestiges of turbolinks by @jcoyne in #3356
- Upgrade tested versions of rails by @jcoyne in #3425
- Test on rails 8.0.0.rc2 by @jcoyne in #3424
- Bump ruby language spec to >= 3.1 by @jcoyne in #3415
- Start testing on Rails 8 final release by @jcoyne in #3437
- Use the released version of i18n-rails by @jcoyne in #3459
- Stop testing with Rails 7.0, which is EOL by @jcoyne in #3498
- Stop testing on Ruby 3.1 it is EOL by @jcoyne in #3541
- Update to use Ruby 3.2 syntax by @jcoyne in #3542
- Update rails to 8.0.2 by @jcoyne in #3589
- Remove code supporting Rails 4 by @jcoyne in #3576
- Run CI on Rails 8.1, for now 8.1.0.rc1 by @jrochkind in #3755
- CI on Rails 8.1.0 now that it's out instead of 8.1.0.rc1 by @jrochkind in #3757
- Update supported Rails versions by @jcoyne in #3764
- Update Ruby and Rails versions in README by @jcoyne in #3777
Miscellaneous
- Begin version 9 development on the main branch by @jcoyne in #3319
- Run prettier on config/locales for consistency by @jcoyne in #3322
- Use plural fixture_paths by @jcoyne in #3335
- Consolidate generated additions to the User class by @jcoyne in #3341
- Use a valid command to test for the existence of docker compose by @jcoyne in #3364
- Workaround bug in devise by @jcoyne in #3368
- Remove cruft by @jcoyne in #3384
- Autocorrect Layout/LineContinuationLeadingSpace by @jcoyne in #3396
- Remove deprecations by @jcoyne in #3390
- update release-related text in README by @jrochkind in #3446
- Add a pull request template by @jcoyne in #3480
- [#3484] Add missing argument to Hash default proc by @sandbergja in #3485
- Remove axe exceptions for unused typeahead and bootstrap 4 by @jcoyne in #3451
- rubocop -a by @sandbergja in #3513
- Run tests on ruby 3.4 by @jcoyne in #3527
- Refactor spec to use described_class by @jcoyne in #3528
- Avoid unnecessary initialization of repository by @jcoyne in #3529
- Remove unnecessary require by @jcoyne in #3535
- Reduce config duplication in a test by @jcoyne in #3540
- Add new rubocop rules and correct by @jcoyne in #3543
- Use the safe navigation operator by @jcoyne in #3545
- Remove empty file by @jcoyne in #3546
- Separate into reusable workflows so we can schedule CI for release branches by @maxkadel in #3570
- Use relative paths for workflows by @maxkadel in #3577
- Run release-8.x on actions from branch by @maxkadel in #3579
- Create a weekly scheduled CI for release-7.x branch by @maxkadel in #3582
- Remove unnecessary rubocop ignore by @jcoyne in #3586
- Add new rubocops and regnerate todo by @jcoyne in #3598
- Update rubocops by @jcoyne in #3652
- Allow page title joiner to be configured by @jcoyne in #3663
- update to 9.0.0.beta3 by @dnoneill in #3664
- Enable the JsonPresenter to be configured by @jcoyne in #3705
- Bump version to 9.0.0.beta7 by @jcoyne in #3723
- Fix rubocop Style/RedundantParentheses offense. by @seanaery in #3744
- Update Dockerfile by @lrullo0 in #3747
- bump versions for 9.0.0-beta8 release by @jrochkind in #3761
- Fix broken CI (fix missing comma, and specify ruby version in each matrix entry) by @seanaery in #3779
New Contributors
- @kirkkwang made their first contribution in #3351
- @paulhagon made their first contribution in #3602
- @mksndz made their first contribution in #3711
- @lrullo0 made their first contribution in #3747
Full Changelog: v8.4.0...v9.0.0