Bidirectional text and RTL block layout support for modern Logseq builds.
This plugin ports the important behavior from Logseq PR #12526 into a plugin that works on newer Logseq versions. It keeps the implementation deliberately small: infer each block's direction from its rendered content, apply dir="auto" where Logseq needs browser bidi handling, and patch only the block layout CSS needed for RTL rows.
- Applies
dir="auto"to block content, page title, editor textarea, and Logseq's hidden#mock-texteditor mirror. - Delegates Unicode first-strong direction detection to the browser.
- Uses
dir="auto"and:dir(rtl)on desktop when the graph DOM is accessible. - Uses Logseq API data plus compact block-id-targeted CSS on Logseq web, where the plugin iframe cannot access the host DOM.
- Adds block context-menu actions for automatic, right-to-left, and left-to-right direction; stores forced choices as a hidden Logseq block property.
- Keeps settings minimal; the only plugin setting is debug logging.
This plugin was developed with AI-assisted coding. Changes are still reviewed, tested, and released by the maintainer.
src/direction.ts: browser-native bidi probing and inline/page-reference text extraction.src/desktop-runtime.ts: host-DOMdir="auto"runtime.src/web-fallback-runtime.ts: Logseq web API/CSS fallback runtime.src/host-css.ts: static desktop RTL layout CSS.src/web-fallback-css.ts: compact generated CSS for web fallback block ids.src/base-css.ts: startup CSS composition.
Debug logging reports which runtime is active when enabled. Web row mirroring depends on Logseq's current-page APIs; aggregate routes that expose no current page receive only the static text-direction handling until Logseq supplies block context.
Right-click a block's bullet and choose:
- Automatic direction to remove the override and return to first-strong detection.
- Right-to-left direction to force RTL.
- Left-to-right direction to force LTR.
Context-menu overrides are stored as hidden Logseq properties and shown by a subtle RTL/LTR badge beside the block text. Manually written direction:: rtl, direction:: ltr, and direction:: auto properties remain supported.
pnpm install
pnpm run build
pnpm run devThe Vite server is configured through vite-plugin-domain for:
https://logseq-plugin-bidi.localhost
If the local HTTPS domain has not been trusted yet, install Caddy and run:
sudo caddy trust
caddy runThen install the plugin in Logseq from:
https://logseq-plugin-bidi.localhost
Logseq fetches package.json from that URL and loads the configured dist/index.html entry.
- Enable Developer mode in Logseq.
- Open Plugins > Load unpacked plugin.
- Select this directory:
logseq-plugin-bidi. - After code changes, rebuild and reload the plugin:
pnpm run buildRun the full local check before shipping changes:
pnpm run checkOr run individual steps:
pnpm run typecheck
pnpm run test
pnpm run build- Confirm the package version in
package.json. - Run the local release checks:
pnpm outdated
pnpm run check- Create and push a version tag:
git tag v<package-version>
git push origin v<package-version>- Wait for
.github/workflows/publish.ymlto create the GitHub release fromCHANGELOG.mdand attachlogseq-plugin-bidi.zip. - Install the release ZIP in Logseq and verify desktop and web behavior before submitting to the marketplace.
The release ZIP contains the built plugin files at the archive root:
package.json
README.md
CHANGELOG.md
LICENSE
icon.png
screenshot.png
dist/
Submit the plugin to logseq/marketplace with a package directory like:
packages/logseq-plugin-bidi/
manifest.json
icon.png
Marketplace manifest draft:
{
"title": "Logseq Plugin Bidi",
"description": "Bidirectional text and RTL block layout support for Logseq.",
"author": "yshalsager",
"repo": "yshalsager/logseq-plugin-bidi",
"icon": "icon.png",
"theme": false,
"web": true,
"effect": false,
"supportsDB": true
}Before opening the marketplace PR, make sure the GitHub release has a ZIP asset and the ZIP installs cleanly.
Use debug logging only while diagnosing a direction or layout issue.
If dev reports that port 5173 is already in use, stop the old Vite process first. To inspect or clear local domain mappings:
pnpm run domain:manage