Cómo filtrar, ordenar y paginar una tabla con JavaScript Vanilla

Cuando una tabla HTML contiene muchos registros, encontrar información concreta puede convertirse rápidamente en una tarea incómoda. Añadir un buscador, ordenar las columnas y dividir los resultados en páginas mejora considerablemente la experiencia de uso.
El problema es que implementar cada una de estas funciones por separado puede obligarnos a escribir una gran cantidad de código cada vez que creamos una tabla nueva.
En este tutorial vamos a crear una clase reutilizable llamada TableManager, desarrollada únicamente con JavaScript Vanilla, que nos permitirá añadir las siguientes funcionalidades a cualquier tabla HTML:
- Filtrado de registros mediante un campo de búsqueda.
- Ordenación ascendente y descendente por columnas.
- Paginación de resultados.
- Selector de registros por página.
- Comparación automática de textos, números y fechas.
- Navegación accesible mediante teclado.
- Personalización de textos y opciones.
- Actualización de la tabla cuando cambian sus filas.
Todo ello sin instalar librerías externas como DataTables, jQuery o frameworks de JavaScript.

¿Qué vamos a crear?
Partiremos de una tabla HTML normal que contiene una lista de personajes, junto con su identificador y planeta de nacimiento.
Una vez aplicada la clase TableManager, la tabla tendrá automáticamente:
- Un campo para buscar registros.
- Cabeceras pulsables para ordenar los datos.
- Un selector para elegir cuántas filas aparecen por página.
- Botones para navegar entre las distintas páginas.
- Información sobre el número de registros mostrados.
La principal ventaja es que no tendremos que programar estas funciones cada vez. Bastará con incluir el archivo JavaScript e inicializar la clase con unas pocas líneas.
Estructura de archivos del proyecto
Para este ejemplo utilizaremos dos archivos:
/proyecto-tabla
├── index.html
└── tableManager.js
El archivo index.html contiene la tabla y la inicialización del componente.
El archivo tableManager.js contiene la clase TableManager, encargada de añadir toda la funcionalidad.
Crear la tabla HTML
En primer lugar, necesitamos una tabla HTML correctamente estructurada.
Es importante que tenga los elementos <thead> y <tbody>, ya que la clase utiliza la cabecera para activar la ordenación y el cuerpo para gestionar las filas.
Un ejemplo simplificado sería el siguiente:
<table id="myTable">
<thead>
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Planeta de nacimiento</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Iron Man</td>
<td>Tierra</td>
</tr>
<tr>
<td>2</td>
<td>Captain America</td>
<td>Tierra</td>
</tr>
<tr>
<td>3</td>
<td>Thor</td>
<td>Asgard</td>
</tr>
<tr>
<td>4</td>
<td>Hulk</td>
<td>Tierra</td>
</tr>
</tbody>
</table>
Lenguaje del código: HTML, XML (xml)
Podemos añadir tantas filas y columnas como necesitemos. La clase detectará automáticamente las filas existentes en el .<tbody>
El atributo id="myTable" nos permitirá seleccionar la tabla posteriormente desde JavaScript.
Incluir el archivo JavaScript
Al final del documento HTML, antes de cerrar la etiqueta </body>, incluimos el archivo que contiene la clase:
<script src="tablas.js"></script>
Lenguaje del código: HTML, XML (xml)
Después de cargarlo, podemos crear una instancia de TableManager:
<script>
document.addEventListener("DOMContentLoaded", () => {
const tablaPersonajes = new TableManager("#myTable", {
sortable: true,
filterable: true,
pagination: true,
rowsPerPage: 10,
rowsPerPageOptions: [5, 10, 25, 50],
});
});
</script>
Lenguaje del código: JavaScript (javascript)
Con este pequeño bloque de código ya tendremos funcionando el buscador, la ordenación y la paginación.
Cómo funciona la clase TableManager

La clase recibe dos parámetros:
new TableManager(tableSelector, options);Lenguaje del código: JavaScript (javascript)
El primer parámetro identifica la tabla que queremos mejorar.
Podemos utilizar un selector CSS:
new TableManager("#myTable");Lenguaje del código: JavaScript (javascript)
También podemos pasar directamente el elemento HTML:
const tabla = document.getElementById("myTable");
new TableManager(tabla);Lenguaje del código: JavaScript (javascript)
El segundo parámetro es un objeto con las opciones de configuración.
new TableManager("#myTable", {
sortable: true,
filterable: true,
pagination: true,
});Lenguaje del código: JavaScript (javascript)
Si no indicamos ninguna opción, la clase utiliza una configuración predeterminada.
Opciones disponibles
Activar o desactivar la ordenación
La opción sortable determina si se podrá ordenar la tabla pulsando sobre sus cabeceras.
sortable: trueLenguaje del código: JavaScript (javascript)
Para desactivar esta función:
sortable: falseLenguaje del código: JavaScript (javascript)
Cuando la ordenación está activa, el primer clic ordena la columna de forma ascendente y el siguiente la ordena de forma descendente.
La funcionalidad también puede activarse mediante las teclas Enter o espacio cuando la cabecera tiene el foco.
Activar o desactivar el buscador
La opción filterable controla la creación del campo de búsqueda:
filterable: trueLenguaje del código: JavaScript (javascript)
Mientras el usuario escribe, la clase recorre las filas y muestra únicamente aquellas que contienen el texto introducido.
La búsqueda no distingue entre mayúsculas y minúsculas.
Por ejemplo, buscar:
asgard
permitirá localizar registros como Thor, Odin, Hela o Heimdall.
Activar o desactivar la paginación
La opción pagination permite dividir los resultados en páginas:
pagination: trueLenguaje del código: JavaScript (javascript)
Para mostrar todas las filas sin paginación:
pagination: falseLenguaje del código: JavaScript (javascript)
Elegir el número de filas por página
Podemos definir cuántos registros se mostrarán inicialmente:
rowsPerPage: 10Lenguaje del código: HTTP (http)
La tabla mostrará diez filas y ocultará el resto hasta que el usuario cambie de página.
Configurar el selector de registros
La opción rowsPerPageOptions define los valores disponibles dentro del selector:
rowsPerPageOptions: [5, 10, 25, 50]Lenguaje del código: CSS (css)
El usuario podrá elegir mostrar 5, 10, 25 o 50 registros por página.
La clase añade automáticamente el valor configurado en rowsPerPage cuando este no se encuentra dentro del array.
Buscar solamente en determinadas columnas
Por defecto, el buscador comprueba el contenido de todas las columnas.
Podemos limitar la búsqueda mediante filterColumns.
new TableManager("#myTable", {
filterable: true,
filterColumns: [1, 2],
});Lenguaje del código: JavaScript (javascript)
Los índices de las columnas comienzan en cero:
0 → ID
1 → Nombre
2 → Planeta de nacimiento
En este ejemplo, el buscador ignorará la columna del identificador y buscará únicamente en el nombre y en el planeta.
Excluir columnas de la ordenación
En algunas tablas podemos tener columnas que no tenga sentido ordenar, como una columna de botones de edición o eliminación.
Podemos excluirlas mediante excludedSortColumns:
new TableManager("#myTable", {
sortable: true,
excludedSortColumns: [3],
});Lenguaje del código: CSS (css)
En este caso, la cuarta columna no responderá al hacer clic sobre su cabecera.
Aplicar una ordenación inicial
También podemos indicar que la tabla aparezca ordenada automáticamente al cargarse.
new TableManager("#myTable", {
initialSort: {
column: 1,
direction: "asc",
},
});Lenguaje del código: CSS (css)
Esta configuración ordenará inicialmente la segunda columna de forma ascendente.
Para ordenar de manera descendente:
initialSort: {
column: 1,
direction: "desc",
}Lenguaje del código: CSS (css)
Ordenación automática de números, fechas y textos
Uno de los puntos más interesantes de la clase es que intenta detectar el tipo de contenido antes de ordenar los valores.
El orden de comprobación es el siguiente:
- Números.
- Fechas.
- Texto.
Ordenación numérica
La clase puede interpretar valores como:
1000
1.000
1.000,50
1000.50
25 €Lenguaje del código: CSS (css)
Esto evita el problema habitual de ordenar números como si fueran cadenas de texto.
Por ejemplo, una ordenación textual podría colocar 100 antes que 20. Al convertir los valores correctamente a números, la clase mantiene su orden lógico.
Ordenación de fechas
La clase admite inicialmente estos formatos:
2026-07-27
27/07/2026
Las fechas se convierten internamente en marcas de tiempo para poder compararlas correctamente.
Ordenación de texto
Cuando el valor no es un número ni una fecha, se utiliza localeCompare con configuración en español:
valueA.localeCompare(valueB, "es", {
numeric: true,
sensitivity: "base",
});Lenguaje del código: CSS (css)
Esto permite realizar una comparación más natural de textos y evita que las diferencias entre mayúsculas y minúsculas alteren innecesariamente el resultado.
Personalizar los textos del componente
Todos los textos visibles pueden modificarse mediante la propiedad labels.
new TableManager("#myTable", {
labels: {
search: "Filtrar personajes:",
rowsPerPage: "Filas visibles:",
previous: "Atrás",
next: "Adelante",
noResults: "No hay personajes que coincidan con la búsqueda",
},
});Lenguaje del código: CSS (css)
No es necesario definir todos los textos. Podemos sobrescribir solamente los que queramos cambiar.
Las etiquetas disponibles son:
labels: {
search: "Buscar:",
rowsPerPage: "Registros por página:",
previous: "Anterior",
next: "Siguiente",
showing: "Mostrando",
to: "a",
total: "de",
records: "registros",
noResults: "No se encontraron resultados",
}Lenguaje del código: CSS (css)
También podemos personalizar el texto del campo de búsqueda:
filterPlaceholder: "Buscar personaje..."Lenguaje del código: JavaScript (javascript)
Navegación entre páginas
La clase calcula automáticamente el número total de páginas según:
- El número de filas filtradas.
- La cantidad de registros seleccionada por página.
Cuando existen pocas páginas, se muestran todos sus números:
1 2 3 4 5
Cuando hay muchas páginas, se añaden puntos suspensivos:
1 … 5 6 7 … 20
Los botones anterior y siguiente se desactivan automáticamente al llegar a los límites de la paginación.
También aparece un texto informativo similar a este:
Mostrando 1 a 10 de 91 registros
Si aplicamos un filtro, la información se actualiza para reflejar únicamente los resultados encontrados.
Actualizar la tabla dinámicamente
En algunas aplicaciones, las filas pueden añadirse o eliminarse después de crear la instancia de TableManager.
Para informar a la clase de estos cambios podemos utilizar el método refresh().
const tablaPersonajes = new TableManager("#myTable");Lenguaje del código: JavaScript (javascript)
Posteriormente añadimos una nueva fila:
const tbody = document.querySelector("#myTable tbody");
tbody.insertAdjacentHTML(
"beforeend",
`
<tr>
<td>92</td>
<td>Nuevo personaje</td>
<td>Tierra</td>
</tr>
`,
);Lenguaje del código: HTML, XML (xml)
Finalmente actualizamos el componente:
tablaPersonajes.refresh();Lenguaje del código: CSS (css)
El método vuelve a obtener las filas, aplica el filtro actual y actualiza la paginación.
Limpiar el buscador mediante JavaScript
La clase también incluye el método clearFilter(), que permite eliminar el texto de búsqueda y volver a mostrar todos los registros.
tablaPersonajes.clearFilter();Lenguaje del código: CSS (css)
Podemos utilizarlo, por ejemplo, desde un botón externo:
<button type="button" id="clearSearch">
Limpiar búsqueda
</button>Lenguaje del código: HTML, XML (xml)
document
.getElementById("clearSearch")
.addEventListener("click", () => {
tablaPersonajes.clearFilter();
});Lenguaje del código: JavaScript (javascript)
Ejemplo de configuración completa
Una configuración más avanzada podría ser la siguiente:
document.addEventListener("DOMContentLoaded", () => {
const tablaPersonajes = new TableManager("#myTable", {
sortable: true,
filterable: true,
pagination: true,
rowsPerPage: 10,
rowsPerPageOptions: [5, 10, 25, 50],
filterPlaceholder: "Buscar por nombre o planeta...",
filterColumns: [1, 2],
excludedSortColumns: [],
initialSort: {
column: 1,
direction: "asc",
},
labels: {
search: "Buscar personaje:",
rowsPerPage: "Personajes por página:",
previous: "Anterior",
next: "Siguiente",
records: "personajes",
noResults: "No se encontraron personajes",
},
});
});Lenguaje del código: JavaScript (javascript)
Esta configuración:
- Busca solamente en el nombre y el planeta.
- Ordena inicialmente por el nombre.
- Muestra diez personajes por página.
- Permite elegir entre 5, 10, 25 y 50 filas.
- Personaliza los principales textos del componente.
Añadir estilos CSS
La clase genera automáticamente varios elementos y clases CSS. Podemos utilizarlas para adaptar el diseño a nuestra página.
.table-manager {
width: 100%;
}
.table-manager__toolbar {
display: flex;
justify-content: flex-end;
margin-bottom: 1rem;
}
.table-manager__search {
padding: 0.6rem 0.8rem;
border: 1px solid #cbd5e1;
border-radius: 6px;
}
.table-manager table {
width: 100%;
border-collapse: collapse;
}
.table-manager th,
.table-manager td {
padding: 0.75rem;
border: 1px solid #d1d5db;
text-align: left;
}
.table-manager__sortable {
cursor: pointer;
user-select: none;
}
.table-manager__sort-asc::after {
content: " ▲";
}
.table-manager__sort-desc::after {
content: " ▼";
}
.table-manager__pagination {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin-top: 1rem;
flex-wrap: wrap;
}
.table-manager__page-buttons,
.table-manager__number-buttons {
display: flex;
align-items: center;
gap: 0.4rem;
}
.table-manager__button {
padding: 0.5rem 0.75rem;
border: 1px solid #cbd5e1;
border-radius: 5px;
background-color: #ffffff;
cursor: pointer;
}
.table-manager__button:disabled {
cursor: not-allowed;
opacity: 0.5;
}
.table-manager__page-number.is-active {
font-weight: bold;
border-color: #2563eb;
}
.table-manager__no-results td {
padding: 1.5rem;
text-align: center;
}Lenguaje del código: CSS (css)
Estos estilos son solamente un punto de partida. Podemos modificar los colores, espacios y tamaños para integrarlos con el diseño de nuestro proyecto o tema de WordPress.
Accesibilidad del componente
La clase incluye varias mejoras de accesibilidad:
- Las cabeceras ordenables pueden utilizarse con el teclado.
- Se añaden atributos
aria-sortpara indicar la dirección de ordenación. - La página activa utiliza
aria-current="page". - El buscador y el selector tienen etiquetas accesibles.
- La información de paginación utiliza
aria-live="polite".
Estas características permiten que el componente sea más fácil de utilizar para usuarios que navegan mediante teclado o tecnologías de asistencia.
Ventajas de utilizar una clase reutilizable
Podríamos escribir la lógica directamente para una tabla concreta, pero encapsularla dentro de una clase ofrece varias ventajas:
Menos código repetido
Podemos aplicar la misma funcionalidad a varias tablas sin copiar y pegar toda la lógica.
new TableManager("#tablaUsuarios");
new TableManager("#tablaProductos");
new TableManager("#tablaPedidos");Lenguaje del código: JavaScript (javascript)
Configuración independiente
Cada tabla puede utilizar opciones diferentes.
new TableManager("#tablaUsuarios", {
rowsPerPage: 10,
});
new TableManager("#tablaProductos", {
rowsPerPage: 25,
filterColumns: [1, 2],
});
new TableManager("#tablaPedidos", {
initialSort: {
column: 3,
direction: "desc",
},
});Lenguaje del código: CSS (css)
Sin dependencias externas
El componente funciona con JavaScript nativo, por lo que no necesitamos:
- Instalar paquetes.
- Añadir un framework.
- Cargar jQuery.
- Depender de servicios externos.
- Incorporar archivos JavaScript de terceros.
Esto ayuda a mantener el proyecto ligero y facilita entender cómo funciona cada parte.
Limitaciones que debemos tener en cuenta
Esta solución trabaja directamente con las filas existentes en el HTML.
Es apropiada para tablas pequeñas o medianas, pero no es la mejor opción para mostrar decenas de miles de registros.
Cuando tenemos una cantidad muy grande de datos, lo recomendable es realizar el filtrado, la ordenación y la paginación desde el servidor o mediante una API.
En esos casos, el navegador debería solicitar únicamente los registros correspondientes a la página actual.
También debemos tener en cuenta que la clase utiliza el contenido visible de las celdas. Si necesitamos ordenar valores complejos, podemos ampliar el componente para utilizar atributos como:
<td data-sort-value="20260729">
29/07/2026
</td>Lenguaje del código: HTML, XML (xml)

Conclusión
Crear un sistema para filtrar, ordenar y paginar una tabla no requiere necesariamente instalar una biblioteca externa.
Mediante la clase TableManager podemos convertir una tabla HTML convencional en un componente mucho más práctico utilizando solamente JavaScript Vanilla.
Una vez incluido el archivo tableManager.js, la configuración básica se reduce a unas pocas líneas:
new TableManager("#myTable", {
sortable: true,
filterable: true,
pagination: true,
rowsPerPage: 10,
});Lenguaje del código: JavaScript (javascript)
A partir de ahí podemos personalizar las columnas de búsqueda, excluir columnas de la ordenación, cambiar las etiquetas, establecer una ordenación inicial y actualizar las filas dinámicamente.
Este tipo de ejercicio también es una buena forma de aprender conceptos importantes de JavaScript, como las clases, la manipulación del DOM, los eventos, los arrays, la ordenación de datos y la creación de componentes reutilizables.
FAQs
Para ordenar una tabla HTML con JavaScript debes detectar el clic sobre cada cabecera, obtener los valores de la columna seleccionada y reorganizar las filas del <tbody>. La clase TableManager automatiza este proceso y permite alternar entre orden ascendente y descendente simplemente pulsando sobre el encabezado de una columna.
Puedes crear un buscador añadiendo un campo <input type="search"> y escuchando su evento input. Cada vez que el usuario escribe, JavaScript compara el texto introducido con el contenido de las celdas y oculta las filas que no coinciden. TableManager genera automáticamente el buscador y permite limitar la búsqueda a columnas concretas.
Para paginar una tabla sin usar jQuery puedes trabajar directamente con JavaScript Vanilla. El proceso consiste en calcular cuántas páginas son necesarias, ocultar las filas que no pertenecen a la página actual y crear botones para navegar entre ellas. TableManager incluye esta funcionalidad sin depender de librerías externas.
Sí. TableManager puede utilizarse con filas añadidas o eliminadas dinámicamente. Después de modificar el contenido del <tbody>, debes ejecutar el método refresh() para que la clase vuelva a detectar las filas, aplique el filtro actual y actualice la ordenación y la paginación.
DataTables es una biblioteca con muchas funciones avanzadas, pero normalmente requiere cargar archivos adicionales y, según la versión utilizada, puede depender de jQuery. Una solución con JavaScript Vanilla no necesita dependencias externas, suele ser más ligera y ofrece un mayor control sobre el código. Sin embargo, DataTables puede ser más adecuada para proyectos que necesitan funciones complejas ya preparadas.
Para ordenar números y fechas correctamente no debes compararlos únicamente como texto. Los números deben convertirse a valores numéricos y las fechas a objetos Date o marcas de tiempo antes de realizar la comparación. TableManager intenta detectar automáticamente números, importes y fechas en formatos como 2026-07-27 o 27/07/2026.
Después de añadir nuevas filas al <tbody>, debes llamar al método refresh() de la instancia de TableManager. Este método vuelve a recopilar todas las filas, reaplica el filtro activo, regresa a la primera página y actualiza los controles de paginación.tablaPersonajes.refresh();
Sí. TableManager utiliza características estándar de JavaScript compatibles con las versiones modernas de Chrome, Edge, Firefox y Safari. No obstante, podría necesitar ajustes o transpilación si el proyecto debe funcionar en navegadores antiguos que no soporten clases, propagación de objetos, encadenamiento opcional u otras características modernas de JavaScript.