npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

ng-searchix-legacy

v1.1.4

Published

Advanced search interface component for AngularJS 1.5.8+ with keyboard shortcuts and fuzzy search

Downloads

1,527

Readme

ng-searchix-legacy

Advanced search interface component for AngularJS 1.5.8+ with keyboard shortcuts and fuzzy search

A powerful, customizable search component for AngularJS 1.x applications, inspired by modern command palettes like Spotlight and Cmd+K interfaces.

Features

  • Modern UI - Beautiful, responsive search interface
  • ⌨️ Keyboard Shortcuts - Configurable hotkeys (Ctrl+K, Cmd+K, etc.)
  • 🔍 Fuzzy Search - Built-in filtering with optional Fuse.js integration
  • 🎨 Fully Customizable - CSS variables for easy theming
  • 📱 Responsive - Works on desktop and mobile
  • 🚀 Lightweight - No heavy dependencies
  • Accessible - ARIA attributes and keyboard navigation

Installation

NPM

npm install ng-searchix-legacy

Bower

bower install ng-searchix-legacy --save

Or add to your bower.json:

{
  "dependencies": {
    "angular": "^1.5.8",
    "ng-searchix-legacy": "^1.0.0"
  }
}

CDN

<!-- Fuse.js (required) -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

<!-- ng-searchix-legacy CSS -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/ng-searchix-legacy.css">

<!-- ng-searchix-legacy JavaScript -->
<script src="https://unpkg.com/[email protected]/ng-searchix-legacy.js"></script>

Manual

Download the files from dist/ folder:

  • ng-searchix-legacy.js
  • ng-searchix-legacy.css

Quick Start

1. Include Dependencies

<!-- AngularJS 1.5.8+ -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>

<!-- Fuse.js (required for fuzzy search) -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

<!-- ng-searchix-legacy -->
<link rel="stylesheet" href="node_modules/ng-searchix-legacy/dist/ng-searchix-legacy.css">
<script src="node_modules/ng-searchix-legacy/dist/ng-searchix-legacy.js"></script>

Note: Fuse.js is required for fuzzy search functionality. If not included, the library will fall back to simple contains matching.

2. Add Module Dependency

angular.module('myApp', ['ngSearchixLegacy']);

3. Use the Component

<div ng-controller="MyController">
  <ngx-searchix
    items="$ctrl.searchItems"
    on-item-selected="$ctrl.handleSelect($item)"
  ></ngx-searchix>
</div>
angular.module('myApp')
  .controller('MyController', function() {
    var vm = this;

    vm.searchItems = [
      { id: '1', title: 'Dashboard', subtitle: 'View analytics', icon: 'dashboard' },
      { id: '2', title: 'Settings', subtitle: 'Configure app', icon: 'settings' },
      { id: '3', title: 'Profile', subtitle: 'Edit your profile', icon: 'user' }
    ];

    vm.handleSelect = function(item) {
      console.log('Selected:', item);
      // Navigate or perform action
    };
  });

API Reference

Component: <ngx-searchix>

Bindings

| Property | Type | Default | Description | |----------|------|---------|-------------| | items | SearchItem[] | [] | Array of searchable items | | placeholder | string | 'Search...' | Input placeholder text | | hotkey | string | 'ctrl+k' | Keyboard shortcut (e.g., 'ctrl+k', 'cmd+k') | | close-on-select | boolean | true | Close overlay after selection | | show-ms | boolean | false | Show search time in ms | | max-results | number | 50 | Maximum results to display | | icon-template | string | - | Custom icon template URL | | icon-renderer | string | - | Custom result icon renderer URL | | button-template | string | - | Custom trigger button template URL | | emit-on-external-open | boolean | false | Emit event when external link clicked | | on-item-selected | function | - | Callback when item is selected ($item) | | on-opened | function | - | Callback when overlay opens | | on-closed | function | - | Callback when overlay closes |

SearchItem Interface

interface SearchItem {
  id: string;          // Unique identifier
  title: string;       // Main title text
  subtitle?: string;   // Optional subtitle/description
  icon?: string;       // Optional icon key
  href?: string;       // Optional external link
  data?: any;          // Custom data payload
}

Configuration Provider

Configure global defaults:

angular.module('myApp', ['ngSearchixLegacy'])
  .config(function(searchixConfigProvider) {
    searchixConfigProvider.setDefaults({
      placeholder: 'Type to search...',
      hotkey: 'cmd+k',
      closeOnSelect: true,
      maxResults: 100,
      showMs: true
    });
  });

Service: searchixOverlay

Direct control over the search overlay:

angular.module('myApp')
  .controller('MyController', function(searchixOverlay) {
    var vm = this;

    vm.openSearch = function() {
      var unsubscribe = searchixOverlay.open(
        vm.items,
        { placeholder: 'Search...' },
        function onSelect(item) {
          console.log('Selected:', item);
        },
        function onClose() {
          console.log('Closed');
        }
      );

      // Later: unsubscribe() to close
    };

    vm.closeSearch = function() {
      searchixOverlay.close();
    };

    vm.isOpen = function() {
      return searchixOverlay.isOpen();
    };
  });

Customization

Theming with CSS Variables

Override CSS variables to customize appearance:

:root {
  /* Trigger Button */
  --searchix-trigger-bg: #ffffff;
  --searchix-trigger-border: rgba(0, 0, 0, 0.12);
  --searchix-trigger-radius: 8px;

  /* Dialog */
  --searchix-bg: #ffffff;
  --searchix-fg: #111827;
  --searchix-border: rgba(0, 0, 0, 0.08);
  --searchix-width: 640px;

  /* Input */
  --searchix-input-font: 16px;
  --searchix-placeholder: rgba(17, 24, 39, 0.4);

  /* Items */
  --searchix-item-active-bg: rgba(59, 130, 246, 0.08);
  --searchix-item-hover: rgba(0, 0, 0, 0.03);

  /* Footer */
  --searchix-muted: rgba(17, 24, 39, 0.5);
}

Dark Mode Example

[data-theme="dark"] {
  --searchix-bg: #1f2937;
  --searchix-fg: #f3f4f6;
  --searchix-border: rgba(255, 255, 255, 0.1);
  --searchix-placeholder: rgba(243, 244, 246, 0.4);
  --searchix-muted: rgba(243, 244, 246, 0.5);
}

Fuzzy Search with Fuse.js

ng-searchix-legacy now uses Fuse.js for fuzzy search by default. You can customize the search behavior by passing Fuse.js options:

// Configure Fuse.js options globally
searchixConfigProvider.setDefaults({
  fuseOptions: {
    keys: ['title', 'subtitle'],
    threshold: 0.3,        // 0.0 = exact match, 1.0 = match anything
    ignoreLocation: true,  // Search entire string
    minMatchCharLength: 2
  }
});

Or pass options to individual components:

<ngx-searchix
  items="$ctrl.items"
  config="{ fuseOptions: { threshold: 0.2 } }"
  on-item-selected="$ctrl.handleSelect($item)"
></ngx-searchix>

Fuse.js Options Reference

Common options you can configure:

| Option | Type | Default | Description | |--------|------|---------|-------------| | threshold | number | 0.35 | At what point does the match algorithm give up (0.0 = perfect match, 1.0 = match anything) | | keys | string[] | ['title', 'subtitle'] | Keys to search in | | ignoreLocation | boolean | true | Whether to ignore location of match in string | | minMatchCharLength | number | 1 | Minimum number of characters that must be matched | | findAllMatches | boolean | false | When true, matching will continue to the end of a search pattern even if a perfect match has already been located |

See Fuse.js documentation for all available options.

Custom Filter Function

If you need completely custom search logic, you can still provide a custom filter function:

searchixConfigProvider.setDefaults({
  filterFn: function(query, items) {
    // Your custom search implementation
    var q = query.toLowerCase();
    return items.filter(function(item) {
      return item.title.toLowerCase().indexOf(q) !== -1;
    });
  }
});

Note: When filterFn is provided, it will be used instead of the default Fuse.js search.

Custom Templates

Custom Trigger Button

<!-- Define template -->
<script type="text/ng-template" id="custom-button.html">
  <button class="my-custom-button" ng-click="open()">
    🔍 Search ({{ hotkey }})
  </button>
</script>

<!-- Use it -->
<ngx-searchix
  items="$ctrl.items"
  button-template="custom-button.html"
></ngx-searchix>

Custom Icon Renderer

<script type="text/ng-template" id="custom-icon.html">
  <i class="icon icon-{{ $implicit }}"></i>
</script>

<ngx-searchix
  items="$ctrl.items"
  icon-renderer="custom-icon.html"
></ngx-searchix>

Examples

Basic Usage

<ngx-searchix
  items="$ctrl.pages"
  placeholder="Search pages..."
  hotkey="ctrl+k"
  on-item-selected="$ctrl.navigate($item)"
></ngx-searchix>

With External Links

vm.items = [
  {
    id: 'docs',
    title: 'Documentation',
    subtitle: 'Read the docs',
    href: 'https://docs.example.com',
    icon: 'book'
  }
];

Custom Search

vm.searchItems = [
  { id: '1', title: 'JavaScript Guide', tags: ['js', 'tutorial'] },
  { id: '2', title: 'CSS Tips', tags: ['css', 'design'] }
];

searchixConfigProvider.setDefaults({
  filterFn: function(query, items) {
    var q = query.toLowerCase();
    return items.filter(function(item) {
      var titleMatch = item.title.toLowerCase().indexOf(q) !== -1;
      var tagMatch = item.tags.some(function(tag) {
        return tag.indexOf(q) !== -1;
      });
      return titleMatch || tagMatch;
    });
  }
});

Programmatic Control

angular.module('myApp')
  .controller('AppController', function(searchixOverlay) {
    var vm = this;

    // Open from anywhere
    vm.openGlobalSearch = function() {
      searchixOverlay.open(
        vm.globalSearchItems,
        { placeholder: 'Global search...' },
        function(item) {
          vm.handleGlobalSelect(item);
        },
        function() {
          console.log('Search closed');
        }
      );
    };

    // Bind to custom hotkey
    angular.element(document).on('keydown', function(e) {
      if (e.ctrlKey && e.shiftKey && e.key === 'p') {
        e.preventDefault();
        vm.openGlobalSearch();
      }
    });
  });

Using with Bower

1. Install via Bower

bower install ng-searchix-legacy --save

2. Include in HTML

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <!-- AngularJS -->
  <script src="bower_components/angular/angular.min.js"></script>

  <!-- Fuse.js (required for fuzzy search) -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

  <!-- ng-searchix-legacy CSS -->
  <link rel="stylesheet" href="bower_components/ng-searchix-legacy/ng-searchix-legacy.css">

  <!-- ng-searchix-legacy JS -->
  <script src="bower_components/ng-searchix-legacy/ng-searchix-legacy.js"></script>
</head>
<body>
  <!-- Your app -->
</body>
</html>

3. Or use with main-bower-files

// gulpfile.js
var mainBowerFiles = require('main-bower-files');

gulp.task('bower-files', function() {
  return gulp.src(mainBowerFiles())
    .pipe(gulp.dest('dist/vendor'));
});

Using with Gulp

Basic Gulpfile

// gulpfile.js
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var cleanCSS = require('gulp-clean-css');

// Vendor scripts
gulp.task('vendor-js', function() {
  return gulp.src([
    'bower_components/angular/angular.min.js',
    'bower_components/ng-searchix-legacy/ng-searchix-legacy.js'
  ])
  .pipe(concat('vendor.js'))
  .pipe(uglify())
  .pipe(gulp.dest('dist/js'));
});

// Vendor styles
gulp.task('vendor-css', function() {
  return gulp.src([
    'bower_components/ng-searchix-legacy/ng-searchix-legacy.css'
  ])
  .pipe(concat('vendor.css'))
  .pipe(cleanCSS())
  .pipe(gulp.dest('dist/css'));
});

// App scripts
gulp.task('app-js', function() {
  return gulp.src('app/**/*.js')
    .pipe(concat('app.js'))
    .pipe(uglify())
    .pipe(gulp.dest('dist/js'));
});

// Watch
gulp.task('watch', function() {
  gulp.watch('app/**/*.js', ['app-js']);
});

// Build
gulp.task('build', ['vendor-js', 'vendor-css', 'app-js']);

// Default
gulp.task('default', ['build', 'watch']);

Advanced Gulpfile with BrowserSync

// gulpfile.js
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var cleanCSS = require('gulp-clean-css');
var browserSync = require('browser-sync').create();
var mainBowerFiles = require('main-bower-files');

// Paths
var paths = {
  vendor: {
    js: mainBowerFiles('**/*.js'),
    css: mainBowerFiles('**/*.css')
  },
  app: {
    js: 'app/**/*.js',
    css: 'app/**/*.css',
    html: 'app/**/*.html'
  },
  dist: 'dist'
};

// Vendor JS
gulp.task('vendor:js', function() {
  return gulp.src(paths.vendor.js)
    .pipe(concat('vendor.min.js'))
    .pipe(uglify())
    .pipe(gulp.dest(paths.dist + '/js'))
    .pipe(browserSync.stream());
});

// Vendor CSS
gulp.task('vendor:css', function() {
  return gulp.src(paths.vendor.css)
    .pipe(concat('vendor.min.css'))
    .pipe(cleanCSS())
    .pipe(gulp.dest(paths.dist + '/css'))
    .pipe(browserSync.stream());
});

// App JS
gulp.task('app:js', function() {
  return gulp.src(paths.app.js)
    .pipe(concat('app.min.js'))
    .pipe(uglify())
    .pipe(gulp.dest(paths.dist + '/js'))
    .pipe(browserSync.stream());
});

// App CSS
gulp.task('app:css', function() {
  return gulp.src(paths.app.css)
    .pipe(concat('app.min.css'))
    .pipe(cleanCSS())
    .pipe(gulp.dest(paths.dist + '/css'))
    .pipe(browserSync.stream());
});

// HTML
gulp.task('html', function() {
  return gulp.src(paths.app.html)
    .pipe(gulp.dest(paths.dist))
    .pipe(browserSync.stream());
});

// Serve
gulp.task('serve', ['build'], function() {
  browserSync.init({
    server: {
      baseDir: paths.dist
    }
  });

  gulp.watch(paths.app.js, ['app:js']);
  gulp.watch(paths.app.css, ['app:css']);
  gulp.watch(paths.app.html, ['html']);
});

// Build
gulp.task('build', ['vendor:js', 'vendor:css', 'app:js', 'app:css', 'html']);

// Default
gulp.task('default', ['serve']);

Project Structure for Gulp

my-project/
├── app/
│   ├── components/
│   │   └── search/
│   │       ├── search.controller.js
│   │       └── search.html
│   ├── app.module.js
│   ├── app.config.js
│   └── index.html
├── bower_components/
│   ├── angular/
│   └── ng-searchix-legacy/
├── dist/
│   ├── css/
│   │   ├── vendor.min.css
│   │   └── app.min.css
│   ├── js/
│   │   ├── vendor.min.js
│   │   └── app.min.js
│   └── index.html
├── bower.json
├── gulpfile.js
└── package.json

Example app.module.js

// app/app.module.js
(function() {
  'use strict';

  angular
    .module('myApp', [
      'ngSearchixLegacy'
    ])
    .config(searchixConfig);

  searchixConfig.$inject = ['searchixConfigProvider'];

  function searchixConfig(searchixConfigProvider) {
    searchixConfigProvider.setDefaults({
      placeholder: 'Search documentation...',
      hotkey: 'ctrl+k',
      closeOnSelect: true,
      maxResults: 50,
      showMs: true
    });
  }
})();

Example index.html

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <meta charset="UTF-8">
  <title>My AngularJS App</title>

  <!-- Vendor CSS (includes ng-searchix-legacy) -->
  <link rel="stylesheet" href="css/vendor.min.css">

  <!-- App CSS -->
  <link rel="stylesheet" href="css/app.min.css">
</head>
<body ng-controller="MainController as $ctrl">

  <ngx-searchix
    items="$ctrl.searchItems"
    on-item-selected="$ctrl.onSelect($item)"
  ></ngx-searchix>

  <!-- Fuse.js (required for fuzzy search) -->
  <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

  <!-- Vendor JS (includes Angular + ng-searchix-legacy) -->
  <script src="js/vendor.min.js"></script>

  <!-- App JS -->
  <script src="js/app.min.js"></script>
</body>
</html>

Browser Support

  • Chrome/Edge (latest)
  • Firefox (latest)
  • Safari (latest)
  • IE 11+ (with polyfills)

Compatibility

  • AngularJS: 1.5.8 and above
  • Node.js: Not required (browser-only library)

Migration from ng-searchix (Angular 2+)

This library provides the same API as ng-searchix but for AngularJS 1.x:

Angular (2+) version:

<ngx-searchix
  [items]="items"
  (itemSelected)="handleSelect($event)"
></ngx-searchix>

AngularJS version:

<ngx-searchix
  items="$ctrl.items"
  on-item-selected="$ctrl.handleSelect($item)"
></ngx-searchix>

Development

Build

cd projects/ng-searchix-legacy
node build.js

This creates:

  • dist/ng-searchix-legacy.js
  • dist/ng-searchix-legacy.css

Project Structure

ng-searchix-legacy/
├── src/
│   ├── ng-searchix-legacy.module.js    # Main module
│   ├── searchix.component.js           # Trigger component
│   ├── searchix-overlay.service.js     # Overlay service
│   ├── searchix-dialog.directive.js    # Dialog directive
│   ├── ng-searchix-legacy.css          # Styles
│   └── ng-searchix-legacy.d.ts         # TypeScript definitions
├── dist/                                # Build output
├── build.js                             # Build script
├── package.json
└── README.md

License

MIT License

Credits

Based on ng-searchix for Angular 2+.

Ported to AngularJS 1.5.8+ for legacy applications.

Support