Theming and right to left
Step by step — the row and header heights, the font, the colours, the lines, one column or row — see Changing the look. This page is the reference: the stylesheets, every variable, right to left.
The theme
Section titled “The theme”@dzgrid/dom injects the grid’s layout CSS by itself; @dzgrid/theme makes it presentable (colours, lines, header,
hover, selection, focus, popups), light and dark, checked for contrast. Each feature with a look has its own sheet,
loaded after dzgrid.css: columns.css, menu.css, grouping.css, pivot.css, edit.css, range.css,
fill.css, dock.css, columns-panel.css, filters-panel.css, find.css, search.css, print.css,
row-drag.css, pinned-rows.css, row-numbers.css, fresh-rows.css; variables.css for the presentation knobs
(below).
import '@dzgrid/theme/dzgrid.css';import '@dzgrid/theme/menu.css';import '@dzgrid/theme/contrast.css'; // more contrast when the system asks for it- Cascade layer. Every rule sits in the layer
dzgrid: your own classes win without!important. When you layer your own CSS, name the order once, first:@layer theme, base, dzgrid, components, utilities;. With an unlayered reset (Tailwind 3’s preflight, Bootstrap’s Reboot), load the*.unlayered.csscopies instead. - Bridges.
tailwind.css(Tailwind 4),tailwind3.css,bootstrap.css(5.3, followsdata-bs-theme) map the grid’s colours, font and corners to your framework’s. - Showcase themes.
midnight.cssandclinic.css, each with a light and a dark twin;data-dzg-skin="midnight"on a container styles only that area.
Colours and sizes
Section titled “Colours and sizes”Colours are CSS variables only. The palette (shared with tzslot), each a light-dark() pair on :root: --tz-bg,
--tz-bg-raised, --tz-fg, --tz-fg-muted, --tz-border, --tz-accent, --tz-accent-fg, --tz-danger,
--tz-warning, --tz-success. What the grid derives, set on any ancestor of .dzg: --dzg-font, --dzg-radius,
--dzg-cell-padding-inline, --dzg-header-bg, --dzg-row-hover-bg, --dzg-row-selected-bg, --dzg-focus-ring,
--dzg-line, --dzg-pill-radius, --dzg-header-size, --dzg-select-bar, --dzg-flash, --dzg-flash-color —
every one in the table below. This site’s own accent is the grid’s --tz-accent: switch the site to dark and every
demo follows.
:root { --tz-accent: light-dark(#7c3aed, #c4b5fd); }.dzg { --dzg-radius: 6px; --dzg-font: 400 0.875rem/1.45 "Atkinson Hyperlegible", system-ui, sans-serif; }.dzg-cell.is-late { color: var(--tz-danger); }Every variable
Section titled “Every variable”Set any of them on an ancestor of .dzg (or on .dzg), or from code with the theme setting below. Sheet says
which stylesheet reads it: base = dzgrid.css (and the layout @dzgrid/dom injects); variables =
@dzgrid/theme/variables.css, loaded after dzgrid.css (variables.unlayered.css after the unlayered copy) — it
changes nothing by itself; a feature’s sheet is named. Key is the theme setting’s key.
| Variable | Key | What it sets | Default | Sheet |
|---|---|---|---|---|
--tz-bg, --tz-bg-raised, --tz-fg, --tz-fg-muted, --tz-border |
bg, bgRaised, fg, fgMuted, border |
The palette’s surfaces, text and lines | tzslot’s palette | base |
--tz-accent, --tz-accent-fg, --tz-danger, --tz-warning, --tz-success |
accent, accentFg, danger, warning, success |
Accent and tones | tzslot’s palette | base |
--dzg-font |
font |
The grid’s font shorthand: a size and a family at least (400 .875rem/1.45 Inter, sans-serif) |
inherited | base |
--dzg-radius |
radius |
Corners of buttons, popups, tooltips (and the frame) | .375rem |
base |
--dzg-line |
line |
Width of every line | 1px |
base |
--dzg-pill-radius |
pillRadius |
A badge’s corners | 1em |
base |
--dzg-cell-padding-inline |
cellPaddingInline |
Cells’ side padding (× the density) | .5rem |
base |
--dzg-cell-padding-block |
cellPaddingBlock |
A wrapped cell’s top and bottom padding | 0 |
variables |
--dzg-cell-align-block |
cellAlignBlock |
A wrapped or part-drawn cell’s content: start, center, end |
top | variables |
--dzg-cell-font-size |
cellFontSize |
The cells’ text size | the grid’s | variables |
--dzg-num-figures |
numFigures |
Number cells’ digits (normal to turn equal widths off) |
tabular-nums |
base |
--dzg-space |
space |
The spacing unit: header gap ×1, overlay ×2, popup padding ×3, footer ×1 / ×2 | .25rem |
variables |
--dzg-target-min |
targetMin |
The smallest button, grip and toggle (WCAG 2.5.8) | 24px |
base |
--dzg-header-bg |
headerBg |
Header, footer, group rows, buttons | --tz-bg-raised |
base |
--dzg-header-fg |
headerFg |
Header text | --tz-fg |
variables |
--dzg-header-size |
headerSize |
Header text size | 1em |
base |
--dzg-header-weight |
headerWeight |
Header weight | 600 |
variables |
--dzg-header-font-family |
headerFontFamily |
Header font family | the grid’s | variables |
--dzg-header-tracking |
headerTracking |
Header letter spacing (never in Arabic) | normal |
base |
--dzg-header-case |
headerCase |
uppercase titles (Arabic has no case) |
none |
variables |
--dzg-header-align-block |
headerAlignBlock |
A tall header’s title: start, center, end |
center |
variables |
--dzg-header-hover-bg |
headerHoverBg |
A sortable header under the pointer | unchanged | variables |
--dzg-frame |
frame |
The grid’s outer edge (a border; none) |
--dzg-line solid --tz-border |
variables |
--dzg-frame-radius |
frameRadius |
The frame’s corners | --dzg-radius |
variables |
--dzg-row-line |
rowLine |
The line between rows (a border; none) |
as the frame | variables |
--dzg-column-line |
columnLine |
A line between columns (a border) | none |
variables |
--dzg-header-line |
headerLine |
The line under each header row | as the frame | variables |
--dzg-header-separator, --dzg-header-separator-size, --dzg-header-separator-height |
headerSeparator, headerSeparatorSize, headerSeparatorHeight |
The marks between resizable header cells | --tz-border, 2px, 50% |
variables |
--dzg-pinned-column-line |
pinnedColumnLine |
The pinned columns’ edge | as the frame | variables |
--dzg-pinned-shadow |
pinnedShadow |
A box-shadow at that edge while content is under it, written for the start side (mirrored by the grid) |
none | base |
--dzg-detail-line |
detailLine |
A detail panel’s start rule | 3px solid --tz-border |
variables |
--dzg-row-odd-bg |
rowOddBg |
Alternate rows (the 2nd, 4th… shown) | none | base |
--dzg-row-hover-bg, --dzg-row-selected-bg, --dzg-row-active-bg |
rowHoverBg, rowSelectedBg, rowActiveBg |
Row under the pointer, selected, holding the focus | tints of the palette | base |
--dzg-cell-active-bg, --dzg-focus-ring |
cellActiveBg, focusRing |
The focused cell’s tint and ring | accent tints | base |
--dzg-column-hover-bg |
columnHoverBg |
The column under the pointer, with columnHover() |
none (nothing drawn) | columnHover() |
--dzg-focus-width |
focusWidth |
The ring’s width (never under 2 px) | 2px |
variables |
--dzg-select-bar |
selectBar |
A selected row’s bar at its start | 0 |
base |
--dzg-stale-fg, --dzg-context-fg, --dzg-toggle-fg |
staleFg, contextFg, toggleFg |
Rows kept while loading, a tree’s context rows, chevrons | --tz-fg-muted |
base |
--dzg-detail-bg |
detailBg |
A detail panel’s surface | --tz-bg-raised |
base |
--dzg-group-row-bg |
groupRowBg |
Group rows and their footers | --dzg-header-bg |
grouping.css |
--dzg-pinned-bg, --dzg-pinned-line |
pinnedBg, pinnedLine |
Pinned rows’ surface and edge | --tz-bg-raised, --tz-fg-muted |
pinned-rows.css |
--dzg-busy-bar |
busyBar |
The busy bar | --tz-accent |
base |
--dzg-flash-color |
flashColor |
A changed value’s flash | --tz-warning |
base |
--dzg-flash |
— | The flash’s strength, 1 → 0, written on the cell by motion(): not a colour to set |
1 |
base |
--dzg-fresh-color, --dzg-fresh-bg, --dzg-fresh-bar |
freshColor, freshBg, freshBar |
Rows a refresh brought | --tz-success, 14 %, 3px |
fresh-rows.css |
--dzg-saving-color, --dzg-saved-color, --dzg-refused-color, --dzg-refused-bg |
savingColor, savedColor, refusedColor, refusedBg |
Save marks, a refused value | tones | edit.css, base |
--dzg-editor-border |
editorBorder |
An open editor’s frame | --dzg-focus-ring |
edit.css |
--dzg-range-bg, --dzg-range-edge, --dzg-fill-handle |
rangeBg, rangeEdge, fillHandle |
A block of cells, its edge, the fill handle | selection tint, --tz-success |
range.css, fill.css |
--dzg-move-bar, --dzg-resize-mode |
moveBar, resizeMode |
Where a moved column lands; the keyboard resize | --tz-accent |
columns.css |
--dzg-search-mark, --dzg-find-color, --dzg-find-bg, --dzg-find-current-bg, --dzg-find-mark, --dzg-find-mark-current |
searchMark, findColor, findBg, findCurrentBg, findMark, findMarkCurrent |
Search and find marks | palette mixes | search.css, find.css |
--dzg-box-size, --dzg-box-radius |
boxSize, boxRadius |
The selection box (its column keeps its width) | 1rem, .25rem |
variables |
--dzg-box-on-bg, --dzg-box-edge |
boxOnBg, boxEdge |
A ticked box’s fill, an unticked one’s edge | --tz-accent, --tz-fg-muted |
variables |
--dzg-icon-size |
iconSize |
Sort mark, chevrons, grip, funnel, the app’s icons in buttons | each mark’s own (funnel 12px) |
variables, feature layouts |
--dzg-popup-bg, --dzg-popup-shadow |
popupBg, popupShadow |
Filter popups and menus | --tz-bg, a soft shadow |
variables |
--dzg-tooltip-bg, --dzg-tooltip-fg |
tooltipBg, tooltipFg |
The tooltip | --tz-fg on --tz-bg reversed |
variables |
--dzg-tooltip-font-size, --dzg-tooltip-font-family, --dzg-tooltip-font-weight, --dzg-tooltip-line-height |
tooltipFontSize, tooltipFontFamily, tooltipFontWeight, tooltipLineHeight |
The tooltip’s type (1.12.0) | the cells’ size, the grid’s font | base, variables |
--dzg-tooltip-max-width, --dzg-tooltip-padding-block, --dzg-tooltip-padding-inline, --dzg-tooltip-radius |
tooltipMaxWidth, tooltipPaddingBlock, tooltipPaddingInline, tooltipRadius |
The tooltip’s box (1.12.0) | 20rem, 1 and 2 spacing units, --dzg-radius |
variables |
--dzg-tooltip-white-space |
tooltipWhiteSpace |
pre-line keeps the value’s line breaks (1.12.0) |
normal |
variables |
--dzg-tooltip-arrow-size, --dzg-tooltip-arrow-color |
tooltipArrowSize, tooltipArrowColor |
The arrow toward the cell, on the side the tooltip opened (0: none; 1.12.0) |
.375rem, the tooltip’s background |
variables |
--dzg-input-bg, --dzg-input-border |
inputBg, inputBorder |
The filters’ boxes: their surface, their edge (a colour, or none; 1.12.0: never erased by a page’s reset) |
--tz-bg; light: --tz-fg-muted 75 % into --tz-bg, dark: --tz-fg-muted |
base |
--dzg-input-fg, --dzg-input-radius |
inputFg, inputRadius |
The filters’ boxes: text, corners (1.12.0) | --tz-fg, --dzg-radius |
variables |
--dzg-button-bg, --dzg-button-border |
buttonBg, buttonBorder |
Pager, filter footer, retry buttons (Apply keeps the accent) | --dzg-header-bg, --tz-fg-muted |
variables |
--dzg-menu-item-height, --dzg-menu-disabled |
menuItemHeight, menuDisabled |
Menu items (never under 24 px), a disabled one | 32px, --tz-fg-muted |
menu.css, columns.css |
--dzg-panel-bg |
panelBg |
The dock and the filters panel | --tz-bg |
dock.css, filters-panel.css |
--dzg-chip-bg, --dzg-chip-hover-bg, --dzg-control-active-bg |
chipBg, chipHoverBg, controlActiveBg |
Chips; a pressed panel button | accent / text mixes | feature sheets |
--dzg-scrollbar, --dzg-scrollbar-thumb, --dzg-scrollbar-thumb-active |
scrollbar, scrollbarThumb, scrollbarThumbActive |
Thin or system scrollbars, the thumb at rest and under the pointer | thin, --tz-border, --tz-fg-muted |
dzgrid.comfort.css |
--dzg-row-hover-fg, --dzg-row-selected-fg, --dzg-row-active-fg |
rowHoverFg, rowSelectedFg, rowActiveFg |
The text of a row under the pointer, selected, holding the focus; content with its own colour keeps it (1.12.0) | the row’s colour | variables |
--dzg-column-separator, --dzg-column-separator-size, --dzg-column-separator-height |
columnSeparator, columnSeparatorSize, columnSeparatorHeight |
A mark between body columns: its colour, thickness, height (60%: a short centred divider); not after the last column (1.12.0) |
none, --dzg-line, 100% |
variables |
--dzg-last-row-line, --dzg-last-column-line |
lastRowLine, lastColumnLine |
The line under the last row shown, after the last column (borders; 1.12.0) | --dzg-row-line, --dzg-column-line |
variables |
--dzg-header-separator-end |
headerSeparatorEnd |
The resize mark after the last column (transparent drops it; 1.12.0) |
as the others | variables |
--dzg-header-padding-inline |
headerPaddingInline |
Header cells’ side padding (× the density; 1.12.0) | the cells’ | variables |
--dzg-header-button-fg, --dzg-header-button-active-fg |
headerButtonFg, headerButtonActiveFg |
The header’s filter and menu buttons; a filtered column’s funnel (1.12.0) | --tz-fg-muted, --tz-accent |
variables |
--dzg-header-group-line |
headerGroupLine |
A column group’s end line (1.12.0) | as the frame | variables |
--dzg-sort-fg |
sortFg |
The sort marks (1.12.0) | --tz-fg-muted |
variables |
--dzg-button-fg, --dzg-button-radius |
buttonFg, buttonRadius |
Buttons’ text and corners (1.12.0) | --tz-fg, --dzg-radius |
variables |
--dzg-popup-radius, --dzg-popup-border, --dzg-popup-padding |
popupRadius, popupBorder, popupPadding |
Filter popups and menus: corners, edge (a border), padding (1.12.0) | --dzg-radius, as the frame, 3 spacing units |
variables |
--dzg-option-selected-bg |
optionSelectedBg |
A ticked value in a set filter’s list (1.12.0) | none | variables |
--dzg-overlay-fg, --dzg-overlay-bg |
overlayFg, overlayBg |
The loading, no-rows and error message (1.12.0) | --tz-fg-muted, --tz-bg |
variables |
--dzg-footer-fg, --dzg-footer-bg |
footerFg, footerBg |
The pager’s strip (1.12.0) | --tz-fg-muted, --dzg-header-bg |
variables |
Read-only (written by the grid; no key): --dzg-row-height, --dzg-header-height, --dzg-density (.75 compact,
1, 1.25 spacious: the side padding follows the density; .dzg { --dzg-density: 1 } in your own CSS keeps it fixed).
Classes are not an API (1.12.0): the grid’s classes, pseudo-elements, data-* marks and DOM order are internal
and may change in any release. Everything a look needs is a variable above, a theme key or a setting; if one is
missing, ask for it rather than styling an internal class. Your own classes (rowClass, ui.cellClass,
ui.headerClass) stay yours. A dropdown of your own opened inside a filter popup must render inside the popup (it
sits in the top layer: a list appended to body falls beneath it).
The theme setting
Section titled “The theme setting”The demo below sets a few of these keys from code on one grid only: alternate rows, lines between columns, a lighter header weight.
import { createGrid } from '@dzgrid/dom';import { theming } from '@dzgrid/dom/theme';import { EN } from '@dzgrid/dom/locales/en';import '@dzgrid/theme/dzgrid.css';import '@dzgrid/theme/variables.css';
type Hive = { id: string; name: string; frames: number };
const grid = createGrid<Hive>(document.getElementById('hives')!, { rows: [{ id: 'h1', name: 'Orchard hive', frames: 10 }], columns: [{ id: 'name', header: 'Hive' }, { id: 'frames', header: 'Frames', type: 'number' }], getRowId: (h) => h.id, messages: EN, theme: { accent: 'light-dark(#0f766e, #5eead4)', rowOddBg: 'color-mix(in srgb, var(--tz-accent) 6%, var(--tz-bg))', headerWeight: 500, columnLine: 'var(--dzg-line, 1px) solid var(--tz-border)' }, features: [theming()],});grid.update({ theme: { headerWeight: 700 } }); // live: the previous keys not given again are taken awayimport { Component } from '@angular/core';import { DzGrid, type DzgColumnOrGroup } from '@dzgrid/angular';import { theming } from '@dzgrid/dom/theme';import { EN } from '@dzgrid/dom/locales/en';
type Hive = { id: string; name: string; frames: number };
@Component({ selector: 'app-hives', imports: [DzGrid], template: `<dz-grid [rows]="rows" [columns]="columns" [getRowId]="rowId" [messages]="messages" [features]="features" [theme]="theme" />`,})export class Hives { readonly rows: Hive[] = [{ id: 'h1', name: 'Orchard hive', frames: 10 }]; readonly columns: DzgColumnOrGroup<Hive>[] = [{ id: 'name', header: 'Hive' }, { id: 'frames', header: 'Frames', type: 'number' }]; readonly rowId = (h: Hive) => h.id; readonly messages = EN; readonly features = [theming()]; readonly theme = { accent: 'light-dark(#0f766e, #5eead4)', headerWeight: 500, columnLine: 'var(--dzg-line, 1px) solid var(--tz-border)' };}import '@dzgrid/element/define';import type { DzGridElement } from '@dzgrid/element';import { theming } from '@dzgrid/dom/theme';import { EN } from '@dzgrid/dom/locales/en';
type Hive = { id: string; name: string; frames: number };
const grid = document.querySelector<DzGridElement<Hive>>('dz-grid')!;grid.columns = [{ id: 'name', header: 'Hive' }, { id: 'frames', header: 'Frames', type: 'number' }];grid.getRowId = (h) => h.id;grid.messages = EN;grid.features = [theming()];grid.settings = { theme: { accent: 'light-dark(#0f766e, #5eead4)', headerWeight: 500, columnLine: 'var(--dzg-line, 1px) solid var(--tz-border)' } };grid.rows = [{ id: 'h1', name: 'Orchard hive', frames: 10 }];The keys are the table’s; each is written on the grid’s root, so it wins over your stylesheets for that grid only. A
value is a CSS value or a number (600); a key not in the table or a value with ;, {, }, <, \, ! or
url( is told (invalid-setting, path settings.theme.<key>) and left out. Contrast is yours to keep:
npm run check:contrast -- --palette checks a palette file.
The grid draws its own marks (characters and shapes, no file, in the text colour). To draw yours:
import { createGrid } from '@dzgrid/dom';import { theming } from '@dzgrid/dom/theme';import { EN } from '@dzgrid/dom/locales/en';
type Hive = { id: string; name: string; frames: number };const funnel = document.querySelector<SVGSVGElement>('#my-funnel')!; // an <svg> already in the page: copied
createGrid<Hive>(document.getElementById('hives')!, { rows: [{ id: 'h1', name: 'Orchard hive', frames: 10 }], columns: [{ id: 'name', header: 'Hive' }, { id: 'frames', header: 'Frames', type: 'number' }], getRowId: (h) => h.id, messages: EN, icons: { sortAsc: '<svg viewBox="0 0 16 16"><path d="M8 3l5 8H3z"/></svg>', filter: funnel }, features: [theming()],});Names: sortAsc, sortDesc, filter, filterActive (a filtered column’s; else filter in the accent — give it to
keep a mark that is not colour alone), menu, chevron (trees, details, header groups: turned and mirrored as the
default), submenu, grip. An SVG string or element (copied). Its shape is drawn in the mark’s colour and size
(--dzg-icon-size), whatever its own fill. Refused, the default kept and invalid-setting told: anything but <svg>
with shapes, groups, gradients, use and title; a <script>, <style> or <foreignObject>; an on… attribute; a
link or url() outside the icon (only #…); more than 20 000 characters. Drawn as a data: image: a CSP must allow
img-src data:. With injectStyles: false, load ICONS_CSS from @dzgrid/dom/theme too.
Alternate rows, lines, the pinned edge
Section titled “Alternate rows, lines, the pinned edge”.dzg { --dzg-row-odd-bg: color-mix(in srgb, var(--tz-accent) 6%, var(--tz-bg)); /* base */ --dzg-pinned-shadow: 6px 0 6px -4px color-mix(in srgb, var(--tz-fg) 35%, transparent); /* base */ --dzg-column-line: var(--dzg-line, 1px) solid var(--tz-border); /* variables.css */ --dzg-frame: none; /* variables.css */}A header title follows its column’s align (numbers at the end); headerAlign on a column places it otherwise.
Light and dark follow the system; data-theme="light" or data-theme="dark" on any ancestor forces one.
Row height comes from the density setting (compact 28 px, comfortable 32 px, the default, spacious 40 px)
or rowHeight in pixels, which wins. Rows follow the reader’s text zoom. The column menu can offer the density to the
user (columnMenu({ density: true })), and the state keeps it.
Header height: the header rows are one row high unless headerHeight (pixels, 24 at least, live) makes them
taller — { rowHeight: 40, headerHeight: 70 }, Angular [headerHeight]="70", <dz-grid header-height="70">. It
sets the column headers’ row and the column-group rows above it (a 70 px header with one group row is 140 px); the
filter row keeps the row height. It follows the text zoom as rows do; vertical titles still grow the row when they
need more. The grid writes it on its root as --dzg-header-height (read-only, as --dzg-row-height).
Since 1.10.0 the group rows have their own height: headerHeight: { columns: 70, groups: 30 } (columns absent: the
row height; groups absent: the columns’). The filter row has its own too: filters({ floating: true, rowHeight: 44 }).
Titles on several lines (headerWrap, columns) grow the column headers’ row; the taller wins.
The grid’s height comes from its container, never from its rows: give the host a height (fixed, a flex or grid
share, 100dvh minus a bar) and the grid fills it whatever its row count (since 1.11.0); the rows scroll inside. There is no « as tall as its rows » mode — the page would
jump each time a filter changes the count.
Column under the pointer (1.10.0): columnHover() from @dzgrid/dom/column-hover writes data-hover-col on the
root and data-col-hover on that column’s cells (mouse and pen only, never the keyboard); the tint is yours:
.dzg { --dzg-column-hover-bg: color-mix(in srgb, var(--tz-accent) 8%, transparent); }Right to left
Section titled “Right to left”Direction is designed in: pinned columns, scrolling, the arrow keys (in Arabic, → moves toward the start, which is on
the right), popups, the tree’s indent and the theme all follow it. Everything in DzGrid speaks of start and
end, never left and right: pinned: 'start', align: 'end', the dock’s start area.
The grid in Arabic (ar-DZ), right to left: the pinned column is on the right, the arrow keys follow the reading order.
import { createGrid } from '@dzgrid/dom';import { AR } from '@dzgrid/dom/locales/ar';
type Souk = { id: string; name: string; stalls: number };
const grid = createGrid<Souk>(document.getElementById('souks')!, { rows: [{ id: 's1', name: 'سوق النجوم', stalls: 48 }], columns: [ { id: 'name', header: 'السوق', pinned: 'start' }, { id: 'stalls', header: 'الدكاكين', type: 'number', align: 'end' }, ], getRowId: (s) => s.id, messages: AR, locale: 'ar-DZ', direction: 'rtl', numerals: 'locale',});
grid.update({ direction: 'auto' }); // follow the nearest `dir` attribute insteadimport { Component } from '@angular/core';import { DzGrid, type DzgColumnOrGroup } from '@dzgrid/angular';import { AR } from '@dzgrid/dom/locales/ar';
type Souk = { id: string; name: string; stalls: number };
@Component({ selector: 'app-souks', imports: [DzGrid], template: `<dz-grid [rows]="rows" [columns]="columns" [getRowId]="rowId" [messages]="messages" locale="ar-DZ" direction="rtl" numerals="locale" />`,})export class Souks { readonly rows: Souk[] = [{ id: 's1', name: 'سوق النجوم', stalls: 48 }]; readonly columns: DzgColumnOrGroup<Souk>[] = [ { id: 'name', header: 'السوق', pinned: 'start' }, { id: 'stalls', header: 'الدكاكين', type: 'number', align: 'end' }, ]; readonly rowId = (s: Souk) => s.id; readonly messages = AR;}<dz-grid locale="ar-DZ" direction="rtl" numerals="locale"></dz-grid>import '@dzgrid/element/define';import type { DzGridElement } from '@dzgrid/element';import { AR } from '@dzgrid/dom/locales/ar';
type Souk = { id: string; name: string; stalls: number };
const grid = document.querySelector<DzGridElement<Souk>>('dz-grid')!;grid.columns = [ { id: 'name', header: 'السوق', pinned: 'start' }, { id: 'stalls', header: 'الدكاكين', type: 'number', align: 'end' },];grid.getRowId = (s) => s.id;grid.messages = AR;grid.rows = [{ id: 's1', name: 'سوق النجوم', stalls: 48 }];direction:'ltr','rtl', or'auto'(the nearest ancestor’sdir).numerals: 'locale'shows the language’s own digits (Arabic-Indic forar); the default'latn'keeps 0–9.- Sorting and searching follow the language: hamza forms, short vowels and tatweel, Arabic-Indic digits.
- Your own CSS should use logical properties as well:
margin-inline-start,inset-inline-end,text-align: start. - Three languages ship:
EN,FR,AR(@dzgrid/dom/locales/*), each feature with its own bundle, plural rules included. Another language is aGridMessagesobject of your own with the same keys;checkMessages(messages)throws, naming the keys that are missing.