Right-to-left charts
FluxGantt can mirror the whole chart for right-to-left locales (Arabic, Hebrew, Persian, Urdu): the
earliest date is at the right, the label column sits at the right edge, bars grow toward the
left, dependency arrows, the progress fill, the collapse toggle and the today line all follow, and
text stays upright and reads right-to-left. It works in both renderers (SVG, and Canvas above 2,000
tasks), in exportSvg() / exportPng(), with drag, resize, link-drawing, zoom and
scrollToTask() / scrollToDate().
It is an opt-in mixin on its own subpath, so a left-to-right chart pays for it with about 0 to 60 bytes (a handful of optional seams) and a chart that composes it pays about 0.4 KiB gzip:
import { createGantt } from '@fluxgantt/core';
import { withRender } from '@fluxgantt/core/render';
import { withInteraction } from '@fluxgantt/core/interaction';
import { withRtl } from '@fluxgantt/core/rtl';
const gantt = withRtl(
withInteraction(
withRender(
createGantt({
tasks,
rtl: true,
locale: 'ar',
ariaLabel: 'خطة المشروع',
}),
),
),
);
gantt.mount(document.getElementById('chart')!);withRtl adds no methods and returns the same instance. Without rtl: true it does nothing at all,
which is why the React and Vue wrappers compose it for you and you only pass the rtl prop:
<FluxGantt tasks={tasks} rtl locale="ar" />A runnable page with Arabic data (and Hebrew via ?lang=he) lives in
examples/plain-html-demo/rtl.html.
What changes
- Direction. The mount container gets
dir="rtl"(and gets its previousdirback when the chart is unmounted or destroyed). The vertical scrollbar moves to the left, the sticky date axis stays aligned with the day columns, and the initial view shows the label column and the start of the project. - Geometry. Layout, hit-testing and dates are computed exactly as before; the painted chart is
mirrored. The data never learns about it, so exports, undo, the critical path and
getTasks()are identical to a left-to-right chart. - Pointer. Dragging a bar toward the left moves it later, toward the right earlier. Resize
still edits the
end, and its grab zone is the bar's visually left edge. The link handle on the right is the start of the task and the one on the left is its end. - Scrolling. In a
dir="rtl"scroll containerscrollLeftis0at the start (right) edge and goes negative toward later dates. FluxGantt's own zoom anchor,scrollToTask()andscrollToDate()already account for that. If your code reads or writes the container'sscrollLeftyourself, use-scrollLeftas the distance from the start edge. - Accessibility. The ARIA grid, row and gridcell order are unchanged (they follow the DOM, which is not mirrored), the critical path is still a dashed outline and the focus ring still follows the focused bar.
Strings and dates
Core ships English only, and rtl does not change that. Date labels follow locale through Intl
(locale: 'ar', 'he', 'fa'...). The two accessible names the library composes are yours through
messages. Hijri and Persian calendars are not supported (dates are Gregorian).
Limits, by design
- Construction-time only. Like
locale,rtlis read once. To switch at runtime, destroy and rebuild the instance (in React or Vue change thekey). - The label column moves with the timeline. It is one mirrored unit; it cannot sit on the opposite side of the chart direction.
- No start-edge resize, as in left-to-right charts.
- Browsers. The negative-
scrollLeftmodel is the evergreen standard (Chrome 85+, Firefox, Safari 14+). The mirrored text placement was verified in Chromium, Firefox, WebKit and Safari 26. Older engines that used other RTL scroll models are not supported. - Exported SVG. The file carries its own transform and
directionattributes and needs no CSS, and browsers render it as the live chart. Some non-browser SVG viewers (Inkscape, resvg) ignore the SVGdirectionproperty and may place the label text differently. - Keyboard. Arrow Left and Right are reserved; when horizontal navigation is added it will be logical (toward the start / end of the row), not physical.