@modracx/ruler-js
v1.0.2
Published
Lightweight on-screen ruler, draggable snap guides and element measurement overlay for web pages, with inch/cm/mm/px units and a crosshair.
Maintainers
Readme
ruler-js
ruler-js is a lightweight, dependency-free layout inspection overlay for
web pages. It gives you on-screen rulers, draggable snap guides, and
Figma-style element measurement — in inches, centimetres, millimetres or pixels.
Ships as a plain ES module with no build step, plus an optional jQuery plugin entry point.
- Creator Profile: https://modracx.com/
- GitHub Repository: https://github.com/Modracx/ruler-js
Key Features
Rulers
- Horizontal & vertical rulers with in / cm / mm / px units
- Optional crosshair and live mouse position box
- Auto-adjusts on window resize
Guides
- Drag out of the ruler gutter to drop a guide; drag one back in to delete it
- Snaps to the edges and centres of elements on the page
- Add, list and remove guides programmatically
Measurement
- Hold a modifier and hover an element for its box model (content, padding, margin)
- Click to pin an element, then hover another for the edge-to-edge gaps
Everything else
- Zero dependencies; works standalone or as a jQuery plugin
- TypeScript definitions included
- Each feature can be enabled, configured or used entirely on its own
Installation
npm install ruler-jsFor the jQuery entry point, also install jQuery (an optional peer dependency):
npm install ruler-js jqueryUsage
ES module (bundler or Node-resolved)
import Ruler from "ruler-js";
const container = document.getElementById("rulerContainer");
Ruler.create(container, {
unit: "in",
unitPrecision: 1,
crosshairColor: "red",
measure: true, // opt in to hover measurement
});
// Remove the ruler, guides and measurement layers
Ruler.clear(container);The container must be positioned (position: relative or similar) — every layer
is absolutely positioned inside it.
Named imports work too, and create returns its own cleanup function:
import { create } from "ruler-js";
const cleanup = create(container, { unit: "cm" });
cleanup(); // equivalent to clear(container)Browser, no bundler
ruler-js is ESM-only, so load it with <script type="module"> from a CDN:
<div id="rulerContainer" style="position: relative; height: 400px;"></div>
<script type="module">
import Ruler from "https://esm.sh/ruler-js";
Ruler.create(document.getElementById("rulerContainer"), { unit: "in" });
</script>A classic
<script src="...">global build is not provided — usetype="module"as above.
jQuery
Importing ruler-js/jquery registers $.fn.Ruler:
import $ from "jquery";
import "ruler-js/jquery";
const $el = $("#rulerContainer");
$el.Ruler("create", { unit: "in", measure: true });
$el.Ruler("addGuide", "x", 1.5);
$el.Ruler("getGuides"); // -> [{ id, axis, position, positionPx }]
$el.Ruler("clear");If jQuery is already on window (for example loaded from a CDN), the plugin
registers itself automatically on import. To attach it to a specific jQuery
instance instead, call the exported registrar:
import { registerRulerPlugin } from "ruler-js/jquery";
registerRulerPlugin(myJQuery);Guides
Guides are on by default. Press inside the ruler gutter and drag to pull one out; it snaps to nearby element edges and centres. Drag a guide back into the gutter to delete it.
Ruler.create(container, {
unit: "in",
guides: {
guideColor: "#00a8ff",
snapTolerance: 8,
onChange: (guides) => console.log(guides),
},
});
const id = Ruler.addGuide(container, "x", 1.5); // 1.5in from the gutter edge
Ruler.getGuides(container); // -> [{ id, axis: "x", position: 1.5, positionPx: 162 }]
Ruler.removeGuide(container, id);Guide axes
The axis names the coordinate the guide is positioned along, not the direction
the line runs — so an "x" guide is a vertical line:
| axis | Line runs | Positioned by | Dragged from |
| ------ | ------------ | ------------- | ------------ |
| "x" | vertically | left | left gutter |
| "y" | horizontally | top | top gutter |
Ruler.addGuide(container, "x", 1); // vertical line, 1in from the left
Ruler.addGuide(container, "y", 1); // horizontal line, 1in from the topposition is measured from the inside edge of the gutter in the configured
unit, so it round-trips with addGuide. positionPx is the raw offset from the
container edge. Pass guides: false to disable them.
Measurement
Measurement is off by default because it adds hover chrome. Enable it with
measure: true, then hold the modifier key (Alt by default) and hover
an element to see its box model and size. Click to pin an element; hovering a
second one then shows the horizontal and vertical gaps between them.
Esc unpins.
Ruler.create(container, {
measure: {
modifierKey: "alt", // "alt" | "ctrl" | "shift" | "meta" | null (always on)
unit: "px",
ignoreSelector: ".no-measure",
showMargin: true,
showPadding: true,
},
});API
| Method | Description |
| ------------------------------- | ------------------------------------------------------------------------------ |
| Ruler.create(el, options?) | Draws the ruler, plus guides / measurement when enabled. Returns a cleanup fn. |
| Ruler.clear(el) | Removes every layer and its event listeners from el. |
| Ruler.addGuide(el, axis, pos) | Adds a guide on "x" or "y" at pos in the current unit. Returns its id. |
| Ruler.getGuides(el) | Lists the current guides. |
| Ruler.removeGuide(el, id) | Removes one guide by id. Returns true if one was removed. |
| Ruler.defaults | The default options object. |
| Ruler.pixelsPerInch() | Pixels the browser reports for a CSS 1in element. |
| Ruler.pixelsPerUnit(unit) | Pixels per one unit of unit. |
Each feature also has its own lifecycle if you want one without the others:
import { createRuler, createGuides, createMeasure } from "ruler-js";
createGuides(container, { snapTolerance: 10 }); // guides, no ruler chrome
createMeasure(container, { modifierKey: null }); // measurement, always onPaired teardowns are clearRuler, clearGuides and clearMeasure.
Options
Ruler
| Option | Default | Description |
| ---------------- | ----------- | ----------------------------------------------------- |
| vRuleSize | 18 | Width (in px) of the vertical ruler |
| hRuleSize | 18 | Height (in px) of the horizontal ruler |
| showCrosshair | true | Whether to show the crosshair lines |
| showMousePos | true | Whether to show the floating mouse position box |
| tickColor | "#323232" | Color of the tick marks |
| crosshairColor | "#000" | Color of the crosshair lines |
| crosshairStyle | "dotted" | Line style of the crosshair (solid, dotted, etc.) |
| mouseBoxBg | "#323232" | Background color of the mouse position box |
| mouseBoxColor | "#fff" | Text color of the mouse position box |
| unit | "in" | Measurement unit (in, cm, mm, px) |
| unitPrecision | 1 | Decimal precision for displayed measurements |
Guides — guides: true | false | {…}
| Option | Default | Description |
| ---------------- | ----------- | --------------------------------------------------------- |
| guideColor | "#00a8ff" | Color of the guide lines |
| guideStyle | "solid" | Border style of the guide lines |
| snapTolerance | 5 | Px within which a dragged guide snaps to an edge / centre |
| snapToElements | true | Snap to the bounding boxes of descendants |
| showLabels | true | Show a position label while dragging |
| labelBg | "#00a8ff" | Background color of the drag label |
| labelColor | "#fff" | Text color of the drag label |
| onChange | null | Called with the guide list after any add / move / remove |
Measurement — measure: true | false | {…}
| Option | Default | Description |
| ---------------- | -------------------------- | -------------------------------------------------- |
| modifierKey | "alt" | Modifier to hold; null means always on |
| ignoreSelector | null | Elements matching this selector are never measured |
| showPadding | true | Shade the padding + border box |
| showMargin | true | Shade the margin box |
| highlightColor | "rgba(0,168,255,0.25)" | Fill of the hovered element |
| outlineColor | "#00a8ff" | Outline of the hovered element |
| paddingColor | "rgba(140,200,120,0.35)" | Padding band fill |
| marginColor | "rgba(255,170,90,0.30)" | Margin band fill |
| distanceColor | "#ff3b70" | Color of the distance lines and labels |
| unit | "px" | Measurement unit |
| unitPrecision | 1 | Decimal precision |
Repository Layout
This package lives in the ruler-js/ subfolder of the
Modracx/ruler-js repository:
ruler-js/ # repo root
├── vanilla/ # script-tag build (window.Ruler) — not on npm
├── jquery/ # script-tag build ($.fn.Ruler) — not on npm
└── ruler-js/ # ← this npm package
├── src/
│ ├── core.js # shared unit maths and DOM helpers
│ ├── ruler.js # ruler chrome
│ ├── guides.js # snap guides
│ ├── measure.js # box model + distances
│ ├── index.js # main entry → "ruler-js"
│ └── jquery.js # jQuery entry → "ruler-js/jquery"
├── demo/ # runnable examples (serve over HTTP)
└── package.jsonOnly src/ ships to npm. The top-level vanilla/ and jquery/ folders hold
standalone <script>-tag builds of the same engine, for pages without a bundler.
They are feature-equivalent but ship no TypeScript definitions.
Demos
Runnable examples live in demo/. They use ES modules, so serve the
folder over HTTP rather than opening the files directly:
npx serve .
# then open /demo/vanilla.html or /demo/jquery.htmlNote
The ruler relies on browser-calculated DPI to approximate real-world units. Actual pixel-per-inch (PPI) measurements may vary slightly depending on the display and browser scaling.
License
MIT © Kenneth D'silva (Modracx)
