Sort data alphabetically

Hello,
Is there a way to sort the data alphabetically from A to Z and Z to A? I’d appreciate it if you could share an example.
Regards,

Hi @ykifahh

Yes, you can sort data alphabetically in Handsontable using the columnSorting plugin. It supports both ascending (A > Z) and descending (Z < A) sorting.

Here’s a basic example Rows sorting - JavaScript Data Grid | Handsontable

Clicking the column header will toggle between ascending and descending sort. Third click will remove the filtering entirely.

If you want to trigger it programmatically you can use our plugin’s API

hot.getPlugin('columnSorting').sort({ column: 0, sortOrder: 'asc' }); 
hot.getPlugin('columnSorting').sort({ column: 0, sortOrder: 'desc' }); 

Updated demo Handsontable example - JSFiddle - Code Playground

Thank you for your response. However, this doesn’t work correctly when using the Arabic language. Our system supports multiple languages—it works fine with English, but it doesn’t behave properly with Arabic. I’d be happy to provide an example if you’re interested in addressing this issue.
Thanks in advance

Thank you for the hint. I do not know arabic alphabet but used Claude AI to check it (please tell me if Claude’s feedback is incorrect).

Demo: Handsontable example - JSFiddle - Code Playground

Here we are sorting C column in the ascending order.

Claude feedback

order:
Row 1: تركيا (Turkey)
Row 2: لبنان (Lebanon)
Row 3: لبنان (Lebanon)
Row 4: لبنان (Lebanon)
Row 5: لبنان (Lebanon)
Row 6: مصر (Egypt)
Row 7: مصر (Egypt)
Row 8: مصر (Egypt)
Row 9: مصر (Egypt)
Row 10: مصر (Egypt)
No, column C is not sorted in ascending alphabetical order.
In proper Arabic alphabetical order, it should be:

لبنان (Lebanon) - starts with ل
مصر (Egypt) - starts with م
تركيا (Turkey) - starts with ت

But your data shows تركيا (Turkey) first, followed by لبنان (Lebanon), then مصر (Egypt). This is actually closer to descending order, but even then it's not perfectly sorted since we have one Turkey entry at the top followed by multiple Lebanon entries, then multiple Egypt entries.
So column C is not sorted in ascending alphabetical order.

Thank you for your response. While your example works, it doesn’t perform well with large datasets. Additionally, sorting doesn’t function correctly with English text. Please see the example below.

https://ifps.dtform.com/cp/module/petition/spreadsheet/index.php?form=1

I figured out there is only one record doesn’t match the sorting. I have no idea where is the issue? Any help would be appreciated

Could you please share your current setup?

When I set RTL mode for the table with 100+ rows the last row is sorted correctly handsontable - StackBlitz (tested on Chrome 137/macOS Ventura). I sorted the first column on the right.

Sure, this is the following code I use

const data = <?php echo json_encode($dataArrJson); ?>;
const hot = new Handsontable(container, {
data: data,
layoutDirection: ‘<?php echo htmlspecialchars($language['dir-' . $_SESSION['language']], ENT_QUOTES, 'UTF-8'); ?>’,
language: ‘<?php echo htmlspecialchars($language['spreadsheet-' . $_SESSION['language']], ENT_QUOTES, 'UTF-8'); ?>’,

colHeaders: colHeaders,
columns: headerName.map(item => {
      switch (item.type) {
        case 'text':
          return { type: 'text' };
        case 'number':
          return { type: 'numeric'};
        case 'date':
          return {type: 'date', dateFormat: 'YYYY-MM-DD', filter: true};
        default:
          return { type: 'text' }; 
      }
    }),


rowHeaders: true,
// colHeaders: true,    This will represent A, B C, D instead of the the header name
filters: true,        
dropdownMenu: true,
dropdownMenu: ['alignment','---------', 'filter_by_condition', 'filter_by_value', 'filter_action_bar'],
readOnly: true, // ensures the cells cannot be edited.
contextMenu: ['copy'], // allows copying the selected text from the table using the right-click menu.
copyPaste: true, // Allow copying
// themeName: 'ht-theme-horizon-dark-auto', 
themeName: 'ht-theme-main-dark-auto',
columnSorting: true,
manualColumnMove: true,
height: '96%',
stretchH: 'all',
autoWrapRow: true, 
autoWrapCol: true,
manualColumnResize: false,
manualRowResize: false,

autoRowSize:false,
autoRowSize :false, 
fixedColumnsStart: 2,


afterFilter: function(conditionsStack) {
  // console.log(hot.countRows());
  document.getElementById('totalFilter').textContent = "Total Filter: " + hot.countRows().toLocaleString();

},   
licenseKey: 'non-commercial-and-evaluation' // For non-commercial use only

});