UNPKG

vanillajs-excelike-table

Version:

A user-friendly pure JavaScript table library with Excel-like features, preset configurations, and intuitive column helpers. Vanilla JS implementation - no frameworks required!

1 lines 18.4 kB
.excelike-table-wrapper{font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;position: relative;width: 100%;background: white;font-size: var(--table-font-size, 14px)} .excelike-table-wrapper *{font-size: inherit} .excelike-table{position: relative;display: flex;flex-direction: column;height: 100%;overflow: hidden} .table-loading{position: absolute;top: 0;left: 0;right: 0;bottom: 0;background: rgba(255, 255, 255, 0.8);display: flex;align-items: center;justify-content: center;z-index: 1000;font-size: 14px;color: rgba(0, 0, 0, 0.65)} .table-container{position: relative;overflow: auto;flex: 1;min-height: 0} .table-container.fixed-height{height: 100%} .table-container.fixed-height .table-header{position: sticky;top: 0;z-index: 10;background-color: #fafafa} .table{width: 100%;border-collapse: collapse;background-color: #fff;font-size: 14px;table-layout: fixed} .table.bordered{border: 1px solid #d9d9d9} .table.small{font-size: 12px} .table.large{font-size: 16px} .table-header{background-color: #fafafa;border-bottom: 1px solid #d9d9d9;padding: 0;position: relative;overflow: visible;position: sticky;top: 0;z-index: 100} .table-container.fixed-height .table-header{box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1)} .table.bordered .table-header{border-right: 1px solid #d9d9d9} .table.bordered .table-header:last-child{border-right: none} .header-content{display: flex;align-items: center;justify-content: space-between;padding: 8px 12px;min-height: 20px;position: relative} .header-title{font-weight: 600;color: rgba(0, 0, 0, 0.85);flex: 1;overflow: hidden;text-overflow: ellipsis;white-space: nowrap} .header-controls{display: flex;align-items: center;gap: 4px;flex-shrink: 0} .sort-controls{display: flex;flex-direction: column;align-items: center;gap: 1px;width: 14px;height: 18px} .sort-indicator{width: 14px;height: 18px;position: relative;display: flex;flex-direction: column;align-items: center;justify-content: center;cursor: pointer;transition: all 0.2s} .sort-indicator:hover{background: rgba(24, 144, 255, 0.1);border-radius: 2px} .sort-triangle{width: 0;height: 0;border-style: solid;display: block;margin: 1px 0} .sort-triangle.up{border-left: 4px solid transparent;border-right: 4px solid transparent;border-bottom: 5px solid rgba(0, 0, 0, 0.45);border-top: none} .sort-triangle.down{border-left: 4px solid transparent;border-right: 4px solid transparent;border-top: 5px solid rgba(0, 0, 0, 0.45);border-bottom: none} .sort-triangle.up.active{border-bottom-color: #1890ff} .sort-triangle.down.active{border-top-color: #1890ff} .filter-dropdown-container{position: relative} .filter-btn{background: none;border: none;cursor: pointer;color: rgba(0, 0, 0, 0.45);padding: 2px;width: 16px;height: 16px;display: flex;align-items: center;justify-content: center;transition: all 0.2s;border-radius: 2px} .filter-btn:hover{color: #1890ff;background: rgba(24, 144, 255, 0.1)} .filter-btn.active{color: #1890ff;background: rgba(24, 144, 255, 0.15)} .filter-funnel{width: 12px;height: 14px;position: relative;display: block} .filter-funnel::before{content: '';position: absolute;top: 1px;left: 0;width: 0;height: 0;border-left: 6px solid transparent;border-right: 6px solid transparent;border-top: 5px solid currentColor} .filter-funnel::after{content: '';position: absolute;bottom: 1px;left: 4px;width: 4px;height: 7px;background: currentColor} .filter-dropdown-wrapper{position: fixed;z-index: 9999;min-width: 200px;overflow: visible} .filter-dropdown{background: white;border: 1px solid #d9d9d9;border-radius: 6px;box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);min-width: 250px;max-width: 400px;font-size: 14px;position: relative;display: flex;flex-direction: column;overflow: hidden} .filter-dropdown-header{padding: 8px 12px;border-bottom: 1px solid #f0f0f0;background: #fafafa;border-radius: 6px 6px 0 0;flex-shrink: 0} .filter-dropdown-title{font-weight: 500;color: rgba(0, 0, 0, 0.85)} .filter-dropdown-search{padding: 8px 12px;border-bottom: 1px solid #f0f0f0;flex-shrink: 0} .filter-search-input{width: 100%;padding: 4px 8px;border: 1px solid #d9d9d9;border-radius: 4px;font-size: 14px;outline: none;box-sizing: border-box} .filter-search-input:focus{border-color: #1890ff;box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2)} .filter-dropdown-content{flex: 1;overflow-y: auto;min-height: 0} .filter-option{padding: 4px 12px;border-bottom: 1px solid #f0f0f0} .filter-option:last-child{border-bottom: none} .filter-option.select-all{background: #f9f9f9;font-weight: 500;border-bottom: 1px solid #d9d9d9} .filter-option-label{display: flex;align-items: center;cursor: pointer;padding: 4px 0;user-select: none;justify-content: flex-start} .filter-checkbox{margin-right: 8px;cursor: pointer} .filter-option-text{flex: 1;color: rgba(0, 0, 0, 0.85);text-align: left;overflow: hidden;text-overflow: ellipsis;white-space: nowrap} .filter-option:hover{background: #f5f5f5} .filter-dropdown-footer{padding: 8px 12px;border-top: 1px solid #f0f0f0;display: flex;flex-direction: column;gap: 8px;flex-shrink: 0} .filter-footer-actions{display: flex;justify-content: flex-end;gap: 8px} .filter-btn-confirm{background: #1890ff;color: white;border: none;padding: 4px 12px;border-radius: 4px;cursor: pointer;font-size: 12px;font-weight: 500} .filter-btn-confirm:hover:not(:disabled){background: #40a9ff} .filter-btn-confirm:disabled{background: #f5f5f5;color: rgba(0, 0, 0, 0.25);cursor: not-allowed} .filter-btn-cancel{background: white;color: rgba(0, 0, 0, 0.65);border: 1px solid #d9d9d9;padding: 4px 12px;border-radius: 4px;cursor: pointer;font-size: 12px} .filter-btn-cancel:hover{color: #1890ff;border-color: #1890ff} .filter-btn-clear-column{background: white;color: #1890ff;border: 1px solid #1890ff;padding: 4px 8px;border-radius: 4px;cursor: pointer;font-size: 12px;transition: all 0.2s;align-self: flex-start} .filter-btn-clear-column:hover{background: #e6f7ff;border-color: #40a9ff;color: #40a9ff} .filter-options-list{overflow-y: auto;flex: 1} .filter-dropdown-range{padding: 8px 12px;border-bottom: 1px solid #f0f0f0;background: #fafafa} .range-filter{padding: 12px;background: white;border-radius: 4px;font-size: 14px} .range-inputs{display: flex;gap: 12px;margin-bottom: 16px} .range-input-group{flex: 1;display: flex;flex-direction: column;gap: 4px} .range-label{font-size: 12px;color: rgba(0, 0, 0, 0.65);font-weight: 500} .range-input{width: 100%;padding: 4px 8px;border: 1px solid #d9d9d9;border-radius: 4px;font-size: 14px;outline: none;box-sizing: border-box} .range-input:focus{border-color: #1890ff;box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2)} .range-slider-container{position: relative;padding: 8px 0} .range-slider{position: relative;height: 6px;background: #f0f0f0;border-radius: 3px;margin: 16px 0;cursor: pointer} .range-track{position: absolute;top: 0;height: 100%;background: #1890ff;border-radius: 3px} .range-thumb{position: absolute;top: 50%;transform: translate(-50%, -50%);width: 16px;height: 16px;background: #1890ff;border: 2px solid white;border-radius: 50%;cursor: grab;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);z-index: 2} .range-thumb:hover{transform: translate(-50%, -50%) scale(1.1);box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3)} .date-range-filter{padding: 12px;background: white;border-radius: 4px;font-size: 14px} .date-range-inputs{display: flex;gap: 12px;margin-bottom: 16px} .date-range-input-group{flex: 1;display: flex;flex-direction: column;gap: 4px} .date-range-label{font-size: 12px;color: rgba(0, 0, 0, 0.65);font-weight: 500} .date-range-input{width: 100%;padding: 4px 8px;border: 1px solid #d9d9d9;border-radius: 4px;font-size: 14px;outline: none;box-sizing: border-box} .date-range-input:focus{border-color: #1890ff;box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2)} .date-range-slider-container{position: relative;padding: 8px 0} .date-range-slider{position: relative;height: 6px;background: #f0f0f0;border-radius: 3px;margin: 16px 0;cursor: pointer} .date-range-track{position: absolute;top: 0;height: 100%;background: #1890ff;border-radius: 3px} .date-range-thumb{position: absolute;top: 50%;transform: translate(-50%, -50%);width: 16px;height: 16px;background: #1890ff;border: 2px solid white;border-radius: 50%;cursor: grab;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);z-index: 2} .date-range-thumb:hover{transform: translate(-50%, -50%) scale(1.1);box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3)} .date-filter-content{flex: 1;overflow-y: auto;min-height: 0} .date-filter-group{border-bottom: 1px solid #f0f0f0} .date-filter-group:last-child{border-bottom: none} .date-filter-group .date-filter-group-header{display: flex;align-items: center;padding: 4px 12px;background: #fafafa;font-weight: 500;cursor: pointer;padding-left: 30px !important} .date-filter-children{background: white} .date-filter-item{border-bottom: 1px solid #f0f0f0} .date-filter-item:last-child{border-bottom: none} .expand-btn{background: none;border: none;cursor: pointer;font-size: 12px;color: #1890ff;padding: 0;width: 16px;height: 16px;display: flex;align-items: center;justify-content: center;margin-right: 4px;border-radius: 2px} .expand-btn:hover{background: #e6f7ff} .expand-btn-month{margin-left: 20px} .date-filter-label{display: flex;align-items: center;cursor: pointer;padding: 4px 0;user-select: none;flex: 1;justify-content: flex-start} .date-filter-checkbox{margin-right: 8px;cursor: pointer} .date-filter-text{flex: 1;color: rgba(0, 0, 0, 0.85);text-align: left} .date-filter-item:hover{background: #f5f5f5} .date-filter-group-header:hover{background: #f0f0f0} .date-filter-month{border-bottom: 1px solid #f0f0f0} .date-filter-month:last-child{border-bottom: none} .date-filter-item.date-filter-month .date-filter-month-header{display: flex;align-items: center;padding: 4px 12px;background: #f9f9f9;font-weight: 500;cursor: pointer;padding-left: 32px !important} .date-filter-month-header:hover{background: #f0f0f0} .date-filter-days{background: white} .date-filter-item.date-filter-day{border-bottom: 1px solid #f0f0f0;padding-left: 92px !important} .date-filter-day:last-child{border-bottom: none} .date-expand-controls{padding: 8px 12px;border-bottom: 1px solid #f0f0f0;background: #fafafa} .expand-control-header{display: flex;align-items: center;gap: 8px} .expand-control-label{font-size: 12px;color: rgba(0, 0, 0, 0.65);font-weight: 500} .expand-control-buttons{display: flex;gap: 4px} .expand-control-btn{padding: 4px 8px;border: 1px solid #d9d9d9;background: white;border-radius: 4px;cursor: pointer;font-size: 12px;color: rgba(0, 0, 0, 0.65);transition: all 0.2s;min-width: 32px} .expand-control-btn:hover{border-color: #1890ff;color: #1890ff} .expand-control-btn.active{background: #1890ff;color: white;border-color: #1890ff} .filter-option-count{color: rgba(0, 0, 0, 0.45);font-size: 11px;font-weight: normal} .resize-handle{position: absolute;top: 0;right: 0;bottom: 0;width: 4px;cursor: col-resize;background: transparent;border-right: 2px solid transparent;transition: border-color 0.2s} .resize-handle:hover{border-right-color: #1890ff;cursor: ew-resize} .table-cell{padding: 8px 12px;color: rgba(0, 0, 0, 0.85);word-wrap: break-word;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;position: relative;cursor: pointer} .header-title{font-weight: 600;color: rgba(0, 0, 0, 0.85);flex: 1;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;cursor: pointer} .cell-tooltip{position: absolute;background: rgba(0, 0, 0, 0.85);color: white;padding: 8px 12px;border-radius: 4px;font-size: 12px;white-space: nowrap;z-index: 10000;pointer-events: none;max-width: 300px;word-wrap: break-word;white-space: normal} .resize-tooltip{position: fixed;background: rgba(0, 0, 0, 0.9);color: white;padding: 6px 10px;border-radius: 6px;font-size: 12px;font-weight: 500;z-index: 10000;pointer-events: none;white-space: nowrap;box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);border: 1px solid rgba(255, 255, 255, 0.2);backdrop-filter: blur(4px);transition: opacity 0.2s ease} .resize-tooltip::before{content: '';position: absolute;bottom: -5px;left: 50%;transform: translateX(-50%);width: 0;height: 0;border-left: 5px solid transparent;border-right: 5px solid transparent;border-top: 5px solid rgba(0, 0, 0, 0.9)} .table.bordered .table-cell{border-right: 1px solid #d9d9d9;border-bottom: 1px solid #d9d9d9} .table.bordered .table-cell:last-child{border-right: none} .table.bordered tr:last-child .table-cell{border-bottom: none} .table tbody tr:hover{background-color: #f5f5f5;cursor: pointer} .enhanced-table-pagination{display: flex;justify-content: space-between;align-items: center;padding: 16px 0;margin-top: 16px;border-top: 1px solid #d9d9d9;flex-shrink: 0} .pagination-info{color: rgba(0, 0, 0, 0.65);font-size: 14px} .pagination-controls{display: flex;align-items: center;gap: 12px} .pagination-controls button{padding: 6px 12px;border: 1px solid #d9d9d9;background: #fff;cursor: pointer;border-radius: 4px;font-size: 14px;color: rgba(0, 0, 0, 0.65);transition: all 0.2s} .pagination-controls button:hover:not(:disabled){border-color: #1890ff;color: #1890ff} .pagination-controls button:disabled{opacity: 0.5;cursor: not-allowed} .page-info{color: rgba(0, 0, 0, 0.65);font-size: 14px} .page-size-selector{display: flex;align-items: center;gap: 4px} .page-size-select{padding: 4px 8px;border: 1px solid #d9d9d9;border-radius: 4px;background: #fff;font-size: 14px;color: rgba(0, 0, 0, 0.65);cursor: pointer;transition: border-color 0.2s} .page-size-select:hover{border-color: #1890ff} .page-size-select:focus{outline: none;border-color: #1890ff;box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2)} .table-menu-container{position: relative;display: flex;justify-content: flex-end;margin-bottom: 8px;flex-shrink: 0} .table-menu-wrapper{position: relative} .table-menu-btn{background: #fff;border: 1px solid #d9d9d9;border-radius: 4px;padding: 6px 8px;cursor: pointer;font-size: 16px;transition: all 0.2s} .table-menu-btn:hover{border-color: #1890ff;color: #1890ff} .table-menu-dropdown{position: absolute;top: 100%;right: 0;background: white;border: 1px solid #d9d9d9;border-radius: 4px;box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);z-index: 1000;min-width: 150px;margin-top: 4px} .table-menu-item{padding: 8px 12px;cursor: pointer;font-size: 14px;transition: background-color 0.2s} .table-menu-item:hover{background-color: #f5f5f5} .table-menu-item-submenu{position: relative;display: flex;align-items: center;justify-content: space-between} .submenu-arrow{font-size: 10px;color: rgba(0, 0, 0, 0.45)} .table-submenu-dropdown{position: absolute;right: 100%;top: 0;background: white;border: 1px solid #d9d9d9;border-radius: 4px;box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);min-width: 100px;display: none;z-index: 1001;margin-right: 0} .table-menu-item-submenu:hover .table-submenu-dropdown{display: block} .table-menu-item-current{background-color: #e6f7ff;color: #1890ff;font-weight: 500} .column-settings-overlay{position: fixed;top: 0;left: 0;right: 0;bottom: 0;background: rgba(0, 0, 0, 0.25);z-index: 10000;display: flex;align-items: center;justify-content: center} .column-settings-modal{background: white;border-radius: 8px;box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);width: 400px;max-height: 80vh;display: flex;flex-direction: column} .column-settings-header{display: flex;justify-content: space-between;align-items: center;padding: 16px 20px;border-bottom: 1px solid #f0f0f0} .column-settings-header h3{margin: 0;font-size: 16px;font-weight: 600;color: rgba(0, 0, 0, 0.85)} .close-btn{background: none;border: none;font-size: 20px;cursor: pointer;color: rgba(0, 0, 0, 0.45);padding: 0;width: 22px;height: 22px;display: flex;align-items: center;justify-content: center;border-radius: 2px} .close-btn:hover{color: rgba(0, 0, 0, 0.75);background: rgba(0, 0, 0, 0.06)} .column-settings-content{flex: 1;overflow-y: auto;padding: 16px 20px} .column-list{display: flex;flex-direction: column;gap: 8px} .column-item{display: flex;align-items: center;justify-content: space-between;padding: 8px 0;border-bottom: 1px solid #f0f0f0} .select-all-item{background: #f9f9f9;padding: 8px 12px;margin: -8px -12px 8px -12px;border-bottom: 1px solid #d9d9d9;font-weight: 500} .column-label{display: flex;align-items: center;cursor: pointer;user-select: none;flex: 1} .column-checkbox{margin-right: 8px;cursor: pointer} .column-text{flex: 1;color: rgba(0, 0, 0, 0.85);font-size: 14px} .pin-label{display: flex;align-items: center;margin-left: 10px;cursor: pointer} .pin-checkbox{margin-right: 4px;cursor: pointer} .pin-icon{font-size: 14px;opacity: 0.6} .pin-checkbox:checked + .pin-icon{opacity: 1} .column-settings-footer{padding: 12px 20px;border-top: 1px solid #f0f0f0;display: flex;justify-content: flex-end;gap: 8px} .confirm-btn{background: #1890ff;color: white;border: none;padding: 6px 16px;border-radius: 4px;cursor: pointer;font-size: 14px;font-weight: 500;transition: background-color 0.2s} .confirm-btn:hover:not(:disabled){background: #40a9ff} .cancel-btn{background: white;color: rgba(0, 0, 0, 0.65);border: 1px solid #d9d9d9;padding: 6px 16px;border-radius: 4px;cursor: pointer;font-size: 14px;transition: all 0.2s} .cancel-btn:hover{color: #1890ff;border-color: #1890ff} .pinned-column{box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);background-color: #ffffff !important;z-index: 100} .table-header.pinned-column{background-color: #fafafa !important} .last-pinned-column{border-right: 2px solid #1890ff !important} .filter-dropdown-content::-webkit-scrollbar{width: 6px} .filter-dropdown-content::-webkit-scrollbar-track{background: #f1f1f1} .filter-dropdown-content::-webkit-scrollbar-thumb{background: #c1c1c1;border-radius: 3px} .filter-dropdown-content::-webkit-scrollbar-thumb:hover{background: #a8a8a8} @media (max-width: 768px){.excelike-table-wrapper{font-size: 12px} .header-content{padding: 6px 8px} .table-cell{padding: 6px 8px} .enhanced-table-pagination{flex-direction: column;gap: 12px;align-items: stretch} .pagination-controls{justify-content: center;flex-wrap: wrap} } @media print{.enhanced-table-pagination{display: none} .filter-dropdown-wrapper{display: none} .table-menu-container{display: none} .column-settings-overlay{display: none} .table tbody tr:hover{background-color: transparent} }