Documentation
Custom Icons
Simple Table allows you to override the default icons used for sorting, pagination, row expansion, filtering, and drag-and-drop operations. Use the unified icons prop to customize all icons in one place, maintaining consistent branding across your application.
New in v2.4.1
All icon props have been consolidated into a single icons object for better organization. The new drag icon is used for the drag handle in the column editor.
React TSX
Copy
1import {SimpleTable} from "@simple-table/react";import type { Theme, ReactIconsConfig } from "@simple-table/react";2import { customIconsConfig } from "./custom-icons.demo-data";3import "@simple-table/react/styles.css";45const customIcons: ReactIconsConfig = {6 sortUp: (7 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">8 <path d="M12 19V5M5 12l7-7 7 7" />9 </svg>10 ),11 sortDown: (12 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">13 <path d="M12 5v14M19 12l-7 7-7-7" />14 </svg>15 ),16 filter: (17 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#8b5cf6" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">18 <path d="M3 4h18l-7 8.5V18l-4 2V12.5L3 4z" />19 </svg>20 ),21 expand: (22 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">23 <path d="M9 5l7 7-7 7" />24 </svg>25 ),26 next: (27 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#2563eb" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">28 <path d="M9 5l7 7-7 7" />29 </svg>30 ),31 prev: (32 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#2563eb" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">33 <path d="M15 19l-7-7 7-7" />34 </svg>35 ),36};3738const CustomIconsDemo = ({39 height = "400px",40 theme,41}: {42 height?: string | number;43 theme?: Theme;44}) => {45 return (46 <SimpleTable47 defaultHeaders={customIconsConfig.headers}48 rows={customIconsConfig.rows}49 icons={customIcons}50 height={height}51 theme={theme}52 />53 );54};5556export default CustomIconsDemo;
Vue SFC
Copy
1<script setup lang="ts">2import { h } from "vue";3import { SimpleTable } from "@simple-table/vue";4import type { Theme, VueIconsConfig } from "@simple-table/vue";5import { customIconsConfig } from "./custom-icons.demo-data";6import "@simple-table/vue/styles.css";78const props = withDefaults(defineProps<{ height?: string | number; theme?: Theme }>(), {9 height: "400px",10});1112function iconSvg(pathD: string, color: string, strokeWidth = "2.5") {13 return h(14 "svg",15 {16 width: 14,17 height: 14,18 viewBox: "0 0 24 24",19 fill: "none",20 stroke: color,21 strokeWidth,22 strokeLinecap: "round",23 strokeLinejoin: "round",24 },25 [h("path", { d: pathD })],26 );27}2829const icons: VueIconsConfig = {30 sortUp: iconSvg("M12 19V5M5 12l7-7 7 7", "#6366f1"),31 sortDown: iconSvg("M12 5v14M19 12l-7 7-7-7", "#6366f1"),32 filter: iconSvg("M3 4h18l-7 8.5V18l-4 2V12.5L3 4z", "#8b5cf6", "2"),33 expand: iconSvg("M9 5l7 7-7 7", "#6366f1"),34 next: iconSvg("M9 5l7 7-7 7", "#2563eb"),35 prev: iconSvg("M15 19l-7-7 7-7", "#2563eb"),36};37</script>3839<template>40 <SimpleTable41 :default-headers="customIconsConfig.headers"42 :rows="customIconsConfig.rows"43 :icons="icons"44 :height="props.height"45 :theme="props.theme"46 />47</template>
Angularcustom-icons-demo.component.ts
Copy
1import { Component, Input } from "@angular/core";2import { SimpleTableComponent } from "@simple-table/angular";3import type { AngularHeaderObject, AngularIconsConfig, Row, Theme } from "@simple-table/angular";4import { customIconsConfig } from "./custom-icons.demo-data";5import {6 DemoExpandIconComponent,7 DemoFilterIconComponent,8 DemoNextIconComponent,9 DemoPrevIconComponent,10 DemoSortDownIconComponent,11 DemoSortUpIconComponent,12} from "./table-icons.components";13import "@simple-table/angular/styles.css";1415@Component({16 selector: "custom-icons-demo",17 standalone: true,18 imports: [SimpleTableComponent],19 template: `20 <simple-table21 [rows]="rows"22 [defaultHeaders]="headers"23 [height]="height"24 [theme]="theme"25 [icons]="icons"26 ></simple-table>27 `,28})29export class CustomIconsDemoComponent {30 @Input() height: string | number = "400px";31 @Input() theme?: Theme;3233 readonly rows: Row[] = customIconsConfig.rows;34 readonly headers: AngularHeaderObject[] = customIconsConfig.headers;35 readonly icons: AngularIconsConfig = {36 sortUp: DemoSortUpIconComponent,37 sortDown: DemoSortDownIconComponent,38 filter: DemoFilterIconComponent,39 expand: DemoExpandIconComponent,40 next: DemoNextIconComponent,41 prev: DemoPrevIconComponent,42 };43}444546// custom-icons.demo-data.ts47// Self-contained demo table setup for this example.48import type { AngularHeaderObject, Row } from "@simple-table/angular";495051export const customIconsData: Row[] = [52 { id: 1, name: "Alpha Release", version: "1.0.0", status: "released", downloads: 15420, date: "2024-01-15" },53 { id: 2, name: "Beta Release", version: "1.1.0", status: "released", downloads: 28300, date: "2024-03-22" },54 { id: 3, name: "Hotfix", version: "1.1.1", status: "released", downloads: 31050, date: "2024-04-05" },55 { id: 4, name: "Feature Update", version: "1.2.0", status: "released", downloads: 42100, date: "2024-06-10" },56 { id: 5, name: "Security Patch", version: "1.2.1", status: "released", downloads: 45800, date: "2024-07-18" },57 { id: 6, name: "Major Release", version: "2.0.0", status: "released", downloads: 67200, date: "2024-09-01" },58 { id: 7, name: "Minor Update", version: "2.1.0", status: "beta", downloads: 8900, date: "2024-11-12" },59 { id: 8, name: "Next Release", version: "2.2.0", status: "planned", downloads: 0, date: "2025-01-20" },60];6162export const customIconsHeaders: AngularHeaderObject[] = [63 { accessor: "id", label: "ID", width: 60, type: "number", isSortable: true },64 { accessor: "name", label: "Release", width: 170, type: "string", isSortable: true },65 { accessor: "version", label: "Version", width: 100, type: "string", isSortable: true },66 { accessor: "status", label: "Status", width: 110, type: "string", isSortable: true },67 {68 accessor: "downloads",69 label: "Downloads",70 width: 130,71 type: "number",72 isSortable: true,73 valueFormatter: ({ value }) => (value as number).toLocaleString(),74 },75 {76 accessor: "date",77 label: "Date",78 width: 130,79 type: "date",80 isSortable: true,81 valueFormatter: ({ value }) => new Date(value as string).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }),82 },83];8485export const customIconsConfig = {86 headers: customIconsHeaders,87 rows: customIconsData,88} as const;899091// table-icons.components.ts92import { Component } from "@angular/core";9394@Component({95 standalone: true,96 selector: "demo-icon-sort-up",97 template: `98 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">99 <path d="M12 19V5M5 12l7-7 7 7" />100 </svg>101 `,102})103export class DemoSortUpIconComponent {}104105@Component({106 standalone: true,107 selector: "demo-icon-sort-down",108 template: `109 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">110 <path d="M12 5v14M19 12l-7 7-7-7" />111 </svg>112 `,113})114export class DemoSortDownIconComponent {}115116@Component({117 standalone: true,118 selector: "demo-icon-filter",119 template: `120 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#8b5cf6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">121 <path d="M3 4h18l-7 8.5V18l-4 2V12.5L3 4z" />122 </svg>123 `,124})125export class DemoFilterIconComponent {}126127@Component({128 standalone: true,129 selector: "demo-icon-expand",130 template: `131 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">132 <path d="M9 5l7 7-7 7" />133 </svg>134 `,135})136export class DemoExpandIconComponent {}137138@Component({139 standalone: true,140 selector: "demo-icon-next",141 template: `142 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#2563eb" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">143 <path d="M9 5l7 7-7 7" />144 </svg>145 `,146})147export class DemoNextIconComponent {}148149@Component({150 standalone: true,151 selector: "demo-icon-prev",152 template: `153 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#2563eb" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">154 <path d="M15 19l-7-7 7-7" />155 </svg>156 `,157})158export class DemoPrevIconComponent {}159
Svelte
Copy
1<script lang="ts">2 import { SimpleTable } from "@simple-table/svelte";3 import type { Theme, SvelteIconsConfig } from "@simple-table/svelte";4 import { customIconsConfig } from "./custom-icons.demo-data";5 import IconSortUp from "./icons/IconSortUp.svelte";6 import IconSortDown from "./icons/IconSortDown.svelte";7 import IconFilter from "./icons/IconFilter.svelte";8 import IconExpand from "./icons/IconExpand.svelte";9 import IconNext from "./icons/IconNext.svelte";10 import IconPrev from "./icons/IconPrev.svelte";11 import "@simple-table/svelte/styles.css";1213 let { height = "400px", theme }: { height?: string | number; theme?: Theme } = $props();1415 const icons: SvelteIconsConfig = {16 sortUp: IconSortUp,17 sortDown: IconSortDown,18 filter: IconFilter,19 expand: IconExpand,20 next: IconNext,21 prev: IconPrev,22 };23</script>2425<SimpleTable26 defaultHeaders={customIconsConfig.headers}27 rows={customIconsConfig.rows}28 {icons}29 {height}30 {theme}31/>
Solid TSX
Copy
1import {SimpleTable} from "@simple-table/solid";import type { Theme } from "@simple-table/solid";2import { customIconsConfig } from "./custom-icons.demo-data";3import "@simple-table/solid/styles.css";45const customIcons = {6 sortUp: (7 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">8 <path d="M12 19V5M5 12l7-7 7 7" />9 </svg>10 ),11 sortDown: (12 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">13 <path d="M12 5v14M19 12l-7 7-7-7" />14 </svg>15 ),16 filter: (17 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#8b5cf6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">18 <path d="M3 4h18l-7 8.5V18l-4 2V12.5L3 4z" />19 </svg>20 ),21 expand: (22 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">23 <path d="M9 5l7 7-7 7" />24 </svg>25 ),26 next: (27 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#2563eb" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">28 <path d="M9 5l7 7-7 7" />29 </svg>30 ),31 prev: (32 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#2563eb" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">33 <path d="M15 19l-7-7 7-7" />34 </svg>35 ),36};3738export default function CustomIconsDemo(props: { height?: string | number; theme?: Theme }) {39 return (40 <SimpleTable41 defaultHeaders={customIconsConfig.headers}42 rows={customIconsConfig.rows}43 height={props.height ?? "400px"}44 theme={props.theme}45 icons={customIcons}46 />47 );48}
TypeScriptCustomIconsDemo.ts
Copy
1import { SimpleTableVanilla } from "simple-table-core";2import type { Theme } from "simple-table-core";3import { customIconsConfig, buildVanillaCustomIcons } from "./custom-icons.demo-data";4import "simple-table-core/styles.css";56export function renderCustomIconsDemo(7 container: HTMLElement,8 options?: { height?: string | number; theme?: Theme }9): SimpleTableVanilla {10 const table = new SimpleTableVanilla(container, {11 defaultHeaders: [...customIconsConfig.headers],12 rows: customIconsConfig.rows,13 height: options?.height ?? "400px",14 theme: options?.theme,15 icons: buildVanillaCustomIcons(),16 });17 return table;18}192021// custom-icons.demo-data.ts22// Self-contained demo table setup for this example.23import type { HeaderObject, Row } from "simple-table-core";242526export const customIconsData: Row[] = [27 { id: 1, name: "Alpha Release", version: "1.0.0", status: "released", downloads: 15420, date: "2024-01-15" },28 { id: 2, name: "Beta Release", version: "1.1.0", status: "released", downloads: 28300, date: "2024-03-22" },29 { id: 3, name: "Hotfix", version: "1.1.1", status: "released", downloads: 31050, date: "2024-04-05" },30 { id: 4, name: "Feature Update", version: "1.2.0", status: "released", downloads: 42100, date: "2024-06-10" },31 { id: 5, name: "Security Patch", version: "1.2.1", status: "released", downloads: 45800, date: "2024-07-18" },32 { id: 6, name: "Major Release", version: "2.0.0", status: "released", downloads: 67200, date: "2024-09-01" },33 { id: 7, name: "Minor Update", version: "2.1.0", status: "beta", downloads: 8900, date: "2024-11-12" },34 { id: 8, name: "Next Release", version: "2.2.0", status: "planned", downloads: 0, date: "2025-01-20" },35];3637export const customIconsHeaders: HeaderObject[] = [38 { accessor: "id", label: "ID", width: 60, type: "number", isSortable: true },39 { accessor: "name", label: "Release", width: 170, type: "string", isSortable: true },40 { accessor: "version", label: "Version", width: 100, type: "string", isSortable: true },41 { accessor: "status", label: "Status", width: 110, type: "string", isSortable: true },42 {43 accessor: "downloads",44 label: "Downloads",45 width: 130,46 type: "number",47 isSortable: true,48 valueFormatter: ({ value }) => (value as number).toLocaleString(),49 },50 {51 accessor: "date",52 label: "Date",53 width: 130,54 type: "date",55 isSortable: true,56 valueFormatter: ({ value }) => new Date(value as string).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }),57 },58];5960export const customIconsConfig = {61 headers: customIconsHeaders,62 rows: customIconsData,63} as const;6465export function createSvgIcon(pathD: string, color = "#3b82f6", size = 14): SVGSVGElement {66 const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");67 svg.setAttribute("width", String(size));68 svg.setAttribute("height", String(size));69 svg.setAttribute("viewBox", "0 0 24 24");70 svg.setAttribute("fill", "none");71 svg.setAttribute("stroke", color);72 svg.setAttribute("stroke-width", "2.5");73 svg.setAttribute("stroke-linecap", "round");74 svg.setAttribute("stroke-linejoin", "round");75 const path = document.createElementNS("http://www.w3.org/2000/svg", "path");76 path.setAttribute("d", pathD);77 svg.appendChild(path);78 return svg;79}8081export const ICON_PATHS = {82 sortUp: "M12 19V5M5 12l7-7 7 7",83 sortDown: "M12 5v14M19 12l-7 7-7-7",84 filter: "M3 4h18l-7 8.5V18l-4 2V12.5L3 4z",85 expand: "M9 5l7 7-7 7",86 next: "M9 5l7 7-7 7",87 prev: "M15 19l-7-7 7-7",88} as const;8990export function buildVanillaCustomIcons() {91 return {92 sortUp: createSvgIcon(ICON_PATHS.sortUp, "#6366f1"),93 sortDown: createSvgIcon(ICON_PATHS.sortDown, "#6366f1"),94 filter: createSvgIcon(ICON_PATHS.filter, "#8b5cf6"),95 expand: createSvgIcon(ICON_PATHS.expand, "#6366f1"),96 next: createSvgIcon(ICON_PATHS.next, "#2563eb"),97 prev: createSvgIcon(ICON_PATHS.prev, "#2563eb"),98 };99}100
Basic Implementation
To customize the icons in Simple Table, pass your custom icon components to the respective props. You can use any icon library like Font Awesome, Material Icons, or your own custom SVG icons.
Available Icon Props
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
iconsIconsConfig | Optional | Unified object for configuring all table icons. Provides a cleaner, more organized API for icon customization. | |
icons.sortUpReact.ReactNode | Optional | Custom icon component for ascending sort indicator in column headers. | |
icons.sortDownReact.ReactNode | Optional | Custom icon component for descending sort indicator in column headers. | |
icons.filterReact.ReactNode | Optional | Custom icon component for the column filter button in filterable columns. | |
icons.expandReact.ReactNode | Optional | Custom icon component for collapsed row groups in hierarchical data display. | |
icons.headerExpandReact.ReactNode | Optional | Custom icon component for the expand state of collapsible column headers. | |
icons.headerCollapseReact.ReactNode | Optional | Custom icon component for the collapse state of collapsible column headers. | |
icons.prevReact.ReactNode | Optional | Custom icon component for pagination previous button. | |
icons.nextReact.ReactNode | Optional | Custom icon component for pagination next button. | |
icons.dragReact.ReactNode | Optional | Custom icon component for the drag handle in the column editor. Used for drag-and-drop column reordering. | |
icons.pinnedLeftIconReact.ReactNode | Optional | Column editor icon for pinning a column to the left. | |
icons.pinnedRightIconReact.ReactNode | Optional | Column editor icon for pinning a column to the right. |
Best Practices
- Keep icon sizes consistent for a polished look
- Use colors that match your application's theme
- Ensure icons are clear and intuitive for their purpose
- For row grouping, choose expand icons that clearly indicate the expand/collapse state
- For drag handles, use icons like grip-vertical or drag indicators that suggest draggability
- Consider using the same icon family throughout your application
- Test your icons for visibility against different background colors
- Use the unified
iconsprop to keep all icon configurations in one place