Help Index

Quick access to guides, API, accessibility, and troubleshooting


Test Code

										_parseMarkSpec(spec, base) {
											// spec: "3,7-9,15" 
											const s = new Set();
											if (!spec) return s;
											for (const part of spec.split(',')) {
												const p = part.trim();
												if (!p) continue;
												const m = p.match(/^(\d+)\s*-\s*(\d+)$/);
												if (m) {
													const a = parseInt(m[1],10), b = parseInt(m[2],10);
													const [lo, hi] = a <= b ? [a,b] : [b,a];
													for (let n=lo; n<=hi; n++) s.add(n);
												} else {
													const n = parseInt(p,10);
													if (!isNaN(n)) s.add(n);
												}
											}
											return s;
										}
									

PWAxcode.autoInit();

Markup & Init

Standard Container


Wrap your snippet in a .container.PWAxcode with an optional header/footer and a body that contains exactly one
<pre><code>…</code></pre>
You can set the language on the wrapper or on <code> via data-lang (e.g. js, html, css, json, sql). Per-snippet behavior (wrap, line numbers, theme, etc.) can be configured with data-attributes.


									
									
JS Snippet
console.log('Hello PWAxcode');
Initialize with:
PWAxcode.autoInit();

Bare block (code only).


Use a plain <div class="PWAxcode"> whose textContent is the raw code. No header/footer is rendered. In bare mode the language is chosen in JavaScript (pass lang in options); data-lang is not required.


								
console.log('Hello PWAxcode');
Initialize with:
con = new PWAxcode(document.getElementById('testCode'), { bare: true, lang: 'js', highlight: true });

Initialization.


For standard containers, call PWAxcode.autoInit(); and all matching blocks are upgraded automatically. For bare blocks, instantiate manually. That’s it!

Data-Attributes

This table lists all configurable options for PWAxcode—type and default, what each option does, and the matching HTML data-attribute for auto-init. You can set options in JavaScript or via data-attributes; when both are present, constructor values take precedence. Booleans accept true | false | 1 | 0; numeric sizes accept numbers (px) or CSS lengths (e.g., 420px, 50vh).

Option Type / Default Description Data-attr
height string | number | null
= null
Fixed height. If set, it overrides maxHeight. data-height
maxHeight string | number | null Scrollable maximum height. data-maxheight
toolbarVisible boolean
= true
Show header toolbar.
footerControls string[] | string
= []
Footer controls (e.g. prev,next,hl,fullscreen,progress). data-footer-controls
footerAlign 'start' | 'center' | 'between' | 'end'
= 'between'
Footer controls alignment. data-footer-align
wrap boolean
= false
Soft-wrap long lines. data-wrap
tabSize number
= 2
TAB width in spaces. data-tabsize
tabs 'both' | 'view' | 'none'
= 'both'
TAB expansion target: in view and copy, view only, or keep \t. data-tabs
autoIndent boolean
= true
Auto-format view according to language. data-autoindent
highlight boolean
= false
Start in highlighted (HL) view if true. data-highlight
lang 'auto' | 'js' | 'json' | 'html' | 'css' | 'sql' | 'mysql' | plugin Language; 'auto' tries detection. data-lang
fade boolean
= true
Top/bottom fades when content overflows. data-fade
compressed boolean
= false
Start in compressed mode. data-compressed
markSpec string
= ''
Line highlighting spec (e.g. "3,7-9"). data-mark
lineNumbers boolean
= true
Show line numbers. data-linenumbers
lineNumbersStart number
= 1
Starting offset for numbering. data-linenumbers-start
download boolean
= true
Show download button. data-download
filename string
= ''
Default filename (otherwise from title). data-filename
downloadContent 'view' | 'raw'
= 'view'
Download formatted view or raw content. data-download-content
typingCPS number
= 30
Typing speed (chars per second) for animations. data-typing-cps
autoFormatAfterTyped boolean
= true
Auto-format after a typed animation completes. data-autoformat-after-typed
haptics 'auto' | 'off'
= 'auto'
Mobile vibration feedback. data-haptics
historyLimit number
= 100
Undo/redo buffer size. data-history-limit
theme 'auto' | 'light' | 'dark' | 'funky' | 'relax' | string Initial theme. 'auto' follows system; custom names map to CSS vars. data-theme
bare boolean
= false
Render a bare snippet (no header/footer UI). data-bare
dedent boolean
= true
Trim common leading indentation from the source. data-dedent
ruler boolean
= false
Show a sticky column ruler. data-ruler
rulerStyle 'full' | 'decades'
= 'full'
Tick style: every column or tens only. data-ruler-style
rulerPosition 'top' | 'bottom'
= 'top'
Place the ruler above or below the code. data-ruler-pos
rulerSticky boolean
= true
Keep the ruler visible while scrolling. data-ruler-sticky
showTokens boolean
= false
Outline tokens for debugging/teaching. data-show-tokens

Notes & Tips

  • HTML attributes → JS options.
    HTML attributes (kebab-case) map to constructor options (camelCase). Example: data-footer-controls="prev,next" → footerControls: ['prev','next']. Booleans accept true | false | 1 | 0. Numbers accept plain digits (pixels) or CSS lengths (e.g., 420px, 50vh). Arrays can be comma-separated strings or JSON (e.g., data-footer-controls='["prev","next"]'). Constructor options always override data-attributes.

  • Load code from a URL.
    Inside the code block you can use data-src="https://example.com/snippet.js" to fetch content. If the request succeeds, the response text replaces the inline code; if it fails, the inline code remains unchanged. Ensure the URL is same-origin or CORS-enabled.

Heads-up.


Fetched content is treated as UTF-8 text. HTTP errors (4xx/5xx) or network failures leave the original inline code in place and log a console warning.

Example Mapping:

									
JS Snippet
console.log('Hello PWAxcode');

Equivalent constructor: new PWAxcode(el, { maxHeight: '380px', wrap: true, footerControls: ['prev','next','fullscreen'], theme: 'funky' });

Options

PWAxcode is configurable per-instance and per-snippet. You can pass an options object when you instantiate. Most options have sensible defaults; types are enforced (booleans, numbers, strings, string lists).

Display & Layout

Option Type / Default Description
api.setFontSize(px) px: number
→ number
Sets the font size (bounded by fontMin/fontMax) and reflows the view. Returns the applied size.
api.zoomIn(step?) step?: number
step = fontStep
→ number
Zoom in convenience; increments font by fontStep.
api.zoomOut(step?) step?: number
step = fontStep
→ number
Zoom out convenience; decrements font by fontStep.
api.resetZoom()
→ { fontSize: number, lineHeight: number }
Restores initial font size and line-height.
api.setHeights(opts) { height?: number|string, maxHeight?: number|string }
→ void
Sets a fixed height or a maxHeight for the body scroll area.
api.setTabSize(n) n: number
→ void
Updates the tab stop size (spaces) for both views.
api.setWrap(on) on: boolean
→ void
Enable/disable soft line wrapping.
api.toggleWrap()
→ void
Toggles soft wrap.
api.showLineNumbers(on) on: boolean
→ void
Show/hide line numbers.
api.toggleLineNumbers()
→ void
Toggles line numbers.
api.setLineNumbersStart(n) n: number
→ void
First visible line number.
api.setHighlight(on) on: boolean
→ void
Switch between highlighted (HL) and plain views.
api.toggleHighlight()
→ void
Toggles HL/plain view.
api.showTokens(on = true) on?: boolean
= true
→ void
Overlay token types for debugging tokenization rules.

Navigation & Scrolling

Option Type / Default Description
api.goto(line, opts?) line: number
opts?: { behavior?: 'auto'|'smooth', offset?: number }
behavior = 'auto'
offset = searchOffsetPx
→ void
Scrolls the view so that line is visible; respects folds; reserves space above via offset.
api.scrollUp(lines = 1) lines?: number
= 1
→ number
Scrolls up by visual lines. Returns new scrollTop.
api.scrollDown(lines = 1) lines?: number
= 1
→ number
Scrolls down by visual lines. Returns new scrollTop.
api.lockScroll(state = true) state?: boolean
= true
→ void
Temporarily disables/enables scrolling inside the widget.

Ruler

Option Type / Default Description
api.showRuler(on) on: boolean
→ void
Show/hide the column ruler overlay.
api.toggleRuler()
→ void
Toggles the ruler overlay.
api.setRulerPosition(position) 'top' | 'bottom'
→ void
Sets the ruler position.
api.setRulerStyle(style) 'tens' | 'full'
→ void
Ruler rendering: ticks every 10 (tens) or every column number (full).

Search

Option Type / Default Description
api.search(query, options?) query: string
options?: { caseSensitive?: boolean, regex?: boolean, wholeWord?: boolean, inline?: boolean, inlineHL?: boolean, viewOffsetPx?: number }
→ number
Searches within the current text. Returns the number of matching lines; supports inline fragment highlighting.
api.searchAsync(query, options?) query: string
options?: SearchOptions
→ Promise<number>
Like search, but awaits paints/scrolls so UI is stable.
api.searchThenPopover(query, popoverOptions?, searchOptions?) query: string
popoverOptions?: PopoverOptions
searchOptions?: SearchOptions
→ Promise<number>
Runs searchAsync then opens a popover anchored to the current hit (if any).
api.searchNext()
→ number
Move to next hit. Returns 1-based index or 0 if none.
api.searchPrevious()
→ number
Move to previous hit. Returns 1-based index or 0 if none.
api.searchNextInline()
→ number
Navigate to next inline fragment within the same line.
api.searchPreviousInline()
→ number
Navigate to previous inline fragment within the same line.
api.getSearchPosition(opts?) opts?: { preferInline?: boolean }
→ { type, element, line, rectViewport, rectPage, rectInContainer }
Returns geometry and metadata to align tooltips/popovers with the current hit.
api.clearSearch()
→ void
Clears all search highlights and resets the search cursor.

Marks & Focus

Option Type / Default Description
api.mark(spec) string | number[]
→ void
Marks a set of lines ("1,3,10-15" or [2,4,6]). Passing other types clears.
api.clearMark()
→ void
Clear all line marks.
api.focusLines(start, end, opts?) start: number, end: number
opts?: { className?: string }
→ void
Dim everything except the given line range; applies className (defaults to pxc-dimmed).
api.clearFocus()
→ void
Removes focus dimming.

Range Highlights

Option Type / Default Description
api.addRangeHighlight(spec) { from:{line,col}, to:{line,col}, className?: string }
→ number
Adds an overlay box spanning the given range. Returns an identifier for later removal.
api.clearRangeHighlights(id?) id?: number
→ void
Clear range highlights; when id is provided, removes only that one.

Code Folding

Option Type / Default Description
api.isFoldable(line) line: number
→ boolean
Returns true if the line can start a fold.
api.getFoldableLines()
→ number[]
Builds a fold map (from braces/tags/etc.).
api.foldAt(line) line: number
→ boolean
Collapses (folds) the region starting at line. Returns whether a fold was performed.
api.unfoldAt(line) line: number
→ boolean
Expands the folded region starting at line. Returns whether an unfold occurred.
api.toggleFoldAt(line) line: number
→ boolean
Folds or unfolds depending on current state.
api.unfoldAll()
→ void
Expands every folded region.
api.rebuildFoldMap()
→ void
Recomputes the internal fold map from current text and folding rules.

Popovers & Toasts

Option Type / Default Description
api.toast(message, opts?) message: string
opts?: { type?: 'info'|'success'|'warning'|'error', ms?: number }
→ void
Shows a transient toast message.
api.showPopover(targetOrRect, options?) 'container'|'search'|string|Element|{top,left,width,height,…}
options?: { title?: string|HTMLElement, content?: string|HTMLElement, direction?: 'top'|'right'|'bottom'|'left', autoClose?: number }
→ void
Opens a popover anchored to a named anchor, selector, element, or absolute page-rect.
api.closePopover(immediate = false) immediate?: boolean
= false
→ void
Closes the currently open popover; can bypass transitions.

State & Persistence

Option Type / Default Description
api.getState()
→ State
Returns a serializable snapshot including content, mode, layout, cursor, marks and search cursor.
api.getStateJSON(pretty = false) pretty?: boolean
= false
→ string
Returns the current editor state as JSON; pretty-prints when true.
api.setState(state, opts?) state: State
opts?: { mergeOptions?: boolean, applyContent?: boolean, reSearch?: boolean, allowFullscreen?: boolean }
→ Promise<boolean>
Applies a saved state (merge options, update content, replay search, toggle fullscreen if permitted).
api.setStateJSON(json, opts?) json: string
opts?: …
→ Promise<boolean>
Parses the JSON then calls setState; invalid JSON returns false.
api.setOption(key, value) key: string, value: any
→ void
Updates a single option (see Options table).
api.setOptions(opts) opts: Partial<Options>
→ void
Batch-apply options in a safe order.
api.getOption(key) key: string
→ any
Read one option.
api.getOptions()
→ Options
Returns a shallow copy of all current options.
api.persistDataAttrs()
→ void
Writes a summary of current options back to root.dataset (useful for SSR/automation).

Events

Option Type / Default Description
api.on(type, handler) type: string
handler: (ev: CustomEvent) => void
→ () => void | undefined
Listen to events such as search, toggleHL, fullscreen, player, floatbar, themechange, edit, copy.
api.off(type, handler) type: string
handler: (ev: CustomEvent) => void
→ void
Unsubscribe from a previously registered event.

Options (for setOption / setOptions)

Option Type / Default Description
theme string
= auto
Theme name (dark, light, funky, relax, auto, custom).
lang string
= auto
Language ID or auto for auto-detect.
highlight boolean
= false
Start in highlighted (HL) view.
wrap boolean
= false
Soft-wrap long lines.
tabSize number
= 2
Tab width (spaces).
tabs 'both'|'view'|'none'
= 'both'
Tab expansion policy / which views to render.
lineNumbers boolean
= true
Show line numbers.
lineNumbersStart number
= 1
First visible line number.
height number | string | null
= null
Fixed height of the body container.
maxHeight number | string | null
= null
Maximum scroll height of the body container.
fade boolean
= false
Enable/disable top/bottom fade shadows.
toolbarVisible boolean
= true
Show/hide the header toolbar.
ruler boolean
= false
Show/hide the column ruler.
rulerStyle 'full'|'tens'
= 'tens'
Ruler style.
rulerPosition 'top'|'bottom'
= 'top'
Ruler placement.
download boolean
= true
Enable the download action.
downloadContent 'view'|'raw'
= 'view'
Which text to download.
filename string
= 'code.txt'
Suggested download filename.
floatBar boolean
= true
Show/hide the floating control bar.
floatBarControls string[] | CSV
= —
Which controls to show (same IDs as footerControls).
floatBarInFullscreen boolean
= true
Keep it visible in fullscreen.
floatBarRemember boolean
= false
Remember last position via localStorage.
playerAutoplay boolean
= false
Auto-start step player.
playerLoop boolean
= false
Loop steps.
playerButtons boolean
= true
Show player buttons.
playerProgress boolean
= true
Show progress indicator.
playerShowNotes boolean
= true
Show notes in player.
playerWaitAfterActionMs number
= 0
Delay after each action (ms).
playerClosePopoverOnStop boolean
= true
Auto-close popover when player stops.
playerStopHoldMs number
= 350
Long-press duration to stop (ms).
showTokens boolean
= false
Toggle token overlay.
footerControls string[] | CSV
= —
Footer controls to render.
footerAlign 'left'|'center'|'right'
= 'right'
Footer alignment.
toastPosition 'top'|'bottom'
= 'bottom'
Toast placement.
toastMax number
= 3
Max concurrent toasts.
copyToastMs number
= 1200
Auto-dismiss delay for copy toasts.
autoIndent boolean
= true
Apply basic auto-indentation rules.
searchOffsetPx number
= 64
Default top offset reserved by goto / search-scroll.
fontSize number | null
= null
Base font size in px (fallback to CSS vars when null).
fontLineHeight number | null
= null
Base line-height (fallback to CSS vars when null).
fontMin number
= 10
Minimum font size allowed.
fontMax number
= 28
Maximum font size allowed.
fontStep number
= 2
Increment used by zoomIn/zoomOut.
typingCPS number
= 24
Typing speed used by demos (chars/sec).
autoFormatAfterTyped boolean
= false
Auto-format after user input.
fullscreen boolean
= false
Start in fullscreen mode.
compressed boolean
= false
Start in compressed (chrome-less) mode.
markSpec string
= ''
Initial mark specification (e.g., "1,3,10-15").
dedent boolean
= true
Trim common leading indentation.
locale string
= 'en'
UI locale.
translations object
= —
Custom i18n strings.

Notes & Tips

  • Where to set options
    • JavaScript (constructor):
      new PWAxcode(el, { lang:'js', highlight:true, lineNumbers:false });
    • HTML (auto-init)
    • At runtime:
      pxc.setOption('lineNumbers', true); theme via pxc.setTheme('dark'|'light'|'funky'|'relax'|auto'|customId)
  • Precedence (highest → lowest)
    • Runtime changes (setOption, setTheme)
    • Constructor options
    • Data-attributes on the element
    • Library defaults
  • Theming
    • Pick 'light', 'dark', 'funky', 'relax' or 'auto' at init; switch anytime with setTheme
    • Custom themes can be bundled/registered and selected by id.

Good to know


Options are per-instance; change them without re-creating the component.
Data-attributes are ideal for content sites (static HTML); JS options are best when you need full control or dynamic behavior.

API Methods

This section documents the runtime JavaScript API you can call to control a PWAxcode instance after it’s on the page. You’ll find constructor & helpers, instance controls (rendering, layout, search, folding, ruler).

Display & Layout

api.setFontSize(px: number): number
Sets the font size (bounded by fontMin / fontMax) and reflows the view. Returns the applied size.
api.setFontSize(16);
api.zoomIn(step?: number): number
api.zoomOut(step?: number): number
api.resetZoom(): { fontSize: number, lineHeight: number }
Convenience zoom controls based on fontStep. resetZoom(); restores the initial font and line-height.
api.zoomIn();
api.setHeights({ height?: number|string, maxHeight?: number|string })
Sets a fixed height or a maxHeight for the body scroll area.
api.setHeights({ height: '400px' });
api.setTabSize(n: number)
Updates the tab stop size (spaces) for both views.
function test() { const grid = []; for (let i = 0; i < 3; i++) { for (let j = 0; j < 4; j++) { grid.push(`${i},${j}`) }; } console.log(grid.join(' ')); }
api.setWrap(on: boolean)
api.toggleWrap()
Enable/disable soft line wrapping.
// Intentional ultra-long single line const wrapLine = ["alpha","beta","gamma","delta","epsilon","zeta","eta","theta","iota","kappa","lambda","mu","nu","xi","omicron","pi","rho","sigma","tau","upsilon","phi","chi","psi","omega","alpha2","beta2","gamma2","delta2","epsilon2","zeta2","eta2","theta2","iota2","kappa2","lambda2","mu2","nu2","xi2","omicron2","pi2","rho2","sigma2","tau2","upsilon2","phi2","chi2","psi2","omega2"].map((v,i)=>`${String(i).padStart(3,"0")}-${v}-${btoa(v+Math.random().toString(36).slice(2))}`).join("|"); console.log(wrapLine);
api.showLineNumbers(on: boolean)
api.toggleLineNumbers()
api.setLineNumbersStart(n: number)
Control visibility and numbering of line numbers.
function test() { const grid = []; for (let i = 0; i < 3; i++) { for (let j = 0; j < 4; j++) { grid.push(`${i},${j}`) }; } console.log(grid.join(' ')); }
api.setHighlight(on: boolean)
api.toggleHighlight()
Switch between highlighted (hl) and plain views.
api.toggleHighlight();
api.showTokens(on = true)
Overlay token types for debugging tokenization rules.
api.showTokens();

Navigation & Scrolling

api.goto(lineNumber: number, opts?: { behavior?: 'auto'|'smooth', offset?: number })
Scrolls the view so that lineNumber is visible. If the line is inside a folded region, the fold summary is used as the anchor. The optional offset (defaults to searchOffsetPx) reserves space above.
// Simple task timer class TaskTimer { constructor(){ this.active=null; this.log=new Map(); } start(name){ if(this.active) throw new Error(`Already timing ${this.active.name}`); this.active={ name, at: performance.now() }; } stop(){ if(!this.active) return; const ms=performance.now()-this.active.at; this.log.set(this.active.name,(this.log.get(this.active.name)||0)+ms); this.active=null; } reset(){ this.active=null; this.log.clear(); } top(n=5){ return [...this.log.entries()].sort((a,b)=>b[1]-a[1]).slice(0,n).map(([name,ms],i)=>`${String(i+1).padStart(2,"0")} ${name} ${ms.toFixed(1)}ms`); } } const sleep = ms => new Promise(r=>setTimeout(r,ms)); (async () => { const tt = new TaskTimer(); for (const [name,wait] of [["build",120],["lint",75],["test",180],["deploy",90]]){ tt.start(name); await sleep(wait + Math.random()*50); tt.stop(); } console.log("== Task report =="); for (const line of tt.top(4)) console.log(line); })(); // Quick error demo (double start should throw) try { const x=new TaskTimer(); x.start("A"); x.start("B"); } catch (e) { console.warn("Expected error:", e.message); } console.log("Demo done.");
api.scrollUp(lines = 1): number
api.scrollDown(lines = 1): number
Scrolls up/down by a number of visual lines. Returns the new scrollTop.
// Simple task timer class TaskTimer { constructor(){ this.active=null; this.log=new Map(); } start(name){ if(this.active) throw new Error(`Already timing ${this.active.name}`); this.active={ name, at: performance.now() }; } stop(){ if(!this.active) return; const ms=performance.now()-this.active.at; this.log.set(this.active.name,(this.log.get(this.active.name)||0)+ms); this.active=null; } reset(){ this.active=null; this.log.clear(); } top(n=5){ return [...this.log.entries()].sort((a,b)=>b[1]-a[1]).slice(0,n).map(([name,ms],i)=>`${String(i+1).padStart(2,"0")} ${name} ${ms.toFixed(1)}ms`); } } const sleep = ms => new Promise(r=>setTimeout(r,ms)); (async () => { const tt = new TaskTimer(); for (const [name,wait] of [["build",120],["lint",75],["test",180],["deploy",90]]){ tt.start(name); await sleep(wait + Math.random()*50); tt.stop(); } console.log("== Task report =="); for (const line of tt.top(4)) console.log(line); })(); // Quick error demo (double start should throw) try { const x=new TaskTimer(); x.start("A"); x.start("B"); } catch (e) { console.warn("Expected error:", e.message); } console.log("Demo done.");
api.lockScroll(state = true)
Temporarily disables scrolling inside the widget (useful for modal interactions).
api.lockScroll();

Rule & Line Numbers

api.showRuler(on: boolean)
api.toggleRuler()
Show/hide the column ruler overlay.
api.toggleRuler();
api.setRulerPosition(position: 'top' | 'bottom')
Position of the ruler overlay.
api.setRulerPosition('bottom');
api.setRulerStyle(style: 'tens' | 'full')
Changes how the ruler renders: tens shows ticks every 10 columns, full renders a number for each column.

Notes:


The ruler must be visible to have an effect. Use showRuler(true) or toggleRuler().

function test() { const grid = []; for (let i = 0; i < 3; i++) { for (let j = 0; j < 4; j++) { grid.push(`${i},${j}`) }; } console.log(grid.join(' ')); }

Search API

api.search(query: string, options?: { caseSensitive?: boolean, regex?: boolean, wholeWord?: boolean, inline?: boolean, inlineHL?: boolean, viewOffsetPx?: number }): number
Searches within the current text. Returns the number of matching lines. When inline is true, individual match fragments are highlighted inside lines (and optionally in the highlighted view with inlineHL).
// Simple case-insensitive search with inline markers const matches = api.search("router", { inline: true }); // Jump between hits api.searchNext(); api.searchPrevious();
api.searchAsync(query: string, options?: SearchOptions): Promise<number>
Like search, but waits for paints/scrolls so UI is stable. Resolves to the number of hits.
const hits = await api.searchAsync?.('router', { inline:true, inlineHL:true, viewOffsetPx:64 }); console.log(`query="router" hits=`, hits);
api.searchThenPopover(query: string, popoverOptions?: PopoverOptions, searchOptions?: SearchOptions): Promise<number>
Runs searchAsync and then opens a popover anchored to the current hit (if any).
api.searchThenPopover( 'router', { title:'Match found', content:'Well done!', direction:'bottom' }, { inline:true, inlineHL:true, viewOffsetPx:64 } );
api.searchNext(): number
api.searchPrevious(): number
Moves the current hit pointer forward/backward and scrolls it into view. Returns the 1-based index of the active hit, or 0 if none.
api.searchNext();
api.searchNextInline(): number
api.searchPreviousInline(): number
Navigates between inline match fragments within the same line. Returns the 1-based index within inline fragments, or 0 if none.
api.searchNextInline(); // 1 → 2 → 3 … api.searchPreviousInline(); // … 3 → 2 → 1
api.getSearchPosition(opts?: { preferInline?: boolean }): { type: 'inline'|'line', element: Element, line: number|null, rectViewport, rectPage, rectInContainer }
Returns geometry and metadata suitable for aligning tooltips/popovers with the current hit. When preferInline is true, the inline fragment is used if available; otherwise the whole line anchor is used.
api.search('continue', { inline:true, inlineHL:true, viewOffsetPx: 64 }); const pos = api.getSearchPosition(); // Return pos = { "type": "inline", "element": {}, "line": 7, "rectViewport": { "top": 435.22918701171875, "left": 551.3958740234375, "right": 610.7812919616699, "bottom": 451.22918701171875, "width": 59.38541793823242, "height": 16 }, "rectPage": { "top": 735.2291870117188, "left": 551.3958740234375, "right": 610.7812919616699, "bottom": 751.2291870117188, "width": 59.38541793823242, "height": 16 }, "rectInContainer": { "top": 209.56251525878906, "left": 156.31253051757812, "right": 215.69794845581055, "bottom": 225.56251525878906, "width": 59.38541793823242, "height": 16 } }
api.clearSearch()
Clears all search highlights and resets the search cursor.
api.clearSearch();

Marks & Focus

api.mark(spec: string | number[])
Marks a set of lines. Accepts a comma-separated string of numbers and ranges like "1,3,10-15", or an array of line numbers. Passing a non-string, non-array clears the override.
api.mark("1,3,10-15"); // string spec api.mark([2,4,6]); // numeric form
api.clearMark()
Clear all line marks
api.clearMark();
api.focusLines(start: number, end: number, opts?: { className?: string })
Dim everything except the given line range, applying className (defaults to pxc-dimmed) to the rest.
// Focus lines 12..28 and scroll to api.focusLines(12, 28, { dim: 0.4, scroll: true });
api.clearFocus()
Removes focus dimming.
api.clearFocus()

Range Highlights

api.addRangeHighlight({ from: { line, col }, to: { line, col }, className?: string }): number
Adds an absolutely-positioned overlay box spanning the given range (start/end inclusive). Returns an identifier for later removal.
const id = api.addRangeHighlight({ from:{ line:14, col:8 }, to:{ line:18, col:12 }, className:'pxc-rangehl' // or 'pxc-rangehl green' });
api.clearRangeHighlights(id?: number)
Clear the range highlights with the given id.
const id = api.addRangeHighlight({ from:{ line:14, col:8 }, to:{ line:18, col:12 }, className:'pxc-rangehl' // or 'pxc-rangehl green' }); // Remove api.clearRangeHighlights(id);
api.clearRangeHighlights()
Clears all range highlights.
api.clearRangeHighlights();
function test() { const grid = []; for (let i = 0; i < 3; i++) { for (let j = 0; j < 4; j++) { grid.push(`${i},${j}`) }; } console.log(grid.join(' ')); }

Code Folding

api.isFoldable(line: number): boolean
Check if a row is foldable. Return true if the line can start a fold.
if (api.isFoldable(40)) { api.toggleFoldAt(40); }
api.getFoldableLines(): number[]
Builds a fold map either from braces (JS/CSS/etc.) or from HTML tag structure.
api.getFoldableLines();
api.foldAt(line: number): boolean
Collapses (folds) the region that starts at line. The editor hides all lines in that region except the header. Return true if a fold was performed.
api.foldAt(40);
api.unfoldAt(line: number): boolean
Expands the folded region that starts at line (i.e., makes its hidden lines visible again). Return true if an unfold occurred.
api.unfoldAt(40);
api.toggleFoldAt(line: number): boolean
Convenience method that folds if the region at line is currently open, or unfolds it if it’s currently folded.
api.toggleFoldAt(40);
api.unfoldAll(): void
Expands every folded region in the document, restoring full visibility.
api.unfoldAll();
api.rebuildFoldMap(): void
Recomputes the internal fold map from the current document text and folding rules (e.g., indentation, brackets, language parser).
api.rebuildFoldMap();
function test() { const grid = []; for (let i = 0; i < 3; i++) { for (let j = 0; j < 4; j++) { grid.push(`${i},${j}`) }; } console.log(grid.join(' ')); }

Collapsed lines indicator.


When a region is collapsed, PWAxcode replaces it with a compact summary row that shows how many lines are hidden (e.g., “7 lines collapsed”). Click the summary (or the caret in the gutter) to expand; click again to collapse. The summary keeps line numbering consistent and can be focused and toggled via keyboard (Enter / Space).

Popovers & Toasts

api.toast(message: string, opts?: { type?: 'info'|'success'|'warning'|'error', ms?: number })
Shows a transient toast message.
api.toast({ text:'Code collapsed...', type:'warning', ms:2500, position:'top' });
api.showPopover(targetOrRect: 'container'|'search'|string|Element|{top,left,width,height, ...}, options?: { title?: string|HTMLElement, content?: string|HTMLElement, direction?: 'top'|'right'|'bottom'|'left', autoClose?: number })
Opens a popover anchored either to a named anchor ('container' or the current 'search' hit), a CSS selector, a specific element, or an absolute page-rect. The popover is accessible (role="dialog") and stacked above the widget.
const hits = await api.searchAsync?.('router', { inline:true, inlineHL:true, viewOffsetPx:64 }); if (hits) { const pos = api.getSearchPosition?.(); if (pos &&) { api.showPopover?.(pos.rectPage, { title:'Match', content:`"router" found`, direction:'bottom', autoClose: 1200 }); } }
api.closePopover(immediate = false)
Closes the currently open popover, optionally bypassing transitions.
api.closePopover();
function test() { const grid = []; for (let i = 0; i < 3; i++) { for (let j = 0; j < 4; j++) { grid.push(`${i},${j}`) }; } console.log(grid.join(' ')); }

State & Persistence

api.getState(): State
Returns a serializable snapshot including content, mode, layout, cursor, marks and search cursor.
api.getState();
api.getStateJSON(pretty = false): string
Returns the current editor state as JSON; pass true for pretty-printed (2-space) output.
api.getStateJSON();
api.setState(state: State, opts?: { mergeOptions?: boolean, applyContent?: boolean, reSearch?: boolean, allowFullscreen?: boolean }): Promise<boolean>
Applies a saved state. By default it merges options, updates content, and replays the active search; it can also enter/exit compressed/fullscreen if permitted. Returns true on success.
// Save const state = api.getState(); localStorage.setItem('snipT_state', state); // Restore const saved = localStorage.getItem('snipT_state'); await pxc.setState(saved, { allowFullscreen:true, mergeOptions:true, applyContent:true, reSearch:true });
api.setStateJSON(json: string, opts?: …): Promise<boolean>
Parses the JSON then calls setState; invalid JSON returns false.
// Save const state = api.getState(); localStorage.setItem('snipT_state', JSON.stringify(state)); // Restore const saved = localStorage.getItem('snipT_state'); if (saved) await api.setStateJSON(saved, { mergeOptions: true, applyContent: true, reSearch: true, allowFullscreen: false });
api.setOption(key: string, value: any)
Updates a single option (see full list below). Many options also refresh layout/UI immediately.
api.setOption('lang', 'html');
api.setOptions(opts: Partial<Options>)
Batch-apply options in a safe order (internally calls setOption key-by-key).
// Batch api.setOptions({ wrap:true, tabSize:2, lang:'auto', lineNumbersStart: 5, height: '300px', });
api.getOption(key: string)
api.getOptions(): Options
Read one option or a shallow copy of all current options.
api.getOption("lang");

Options you can pass:


  • wrap: boolean → toggles soft wrap.
  • theme: "dark" | "light" | "auto" | custom → applies theme (built-ins include dark/light/funky/relax).
  • lang: "auto"|string → sets language (auto-detect if "auto").
  • highlight: boolean → switches between highlighted/plain mode and reapplies hits.
  • tabSize: number → updates tab width (rebuilds view when needed).
  • tabs: "both" | "view" | "none" → tab expansion policy; rebuilds view.
  • lineNumbers: boolean → show/hide line numbers.
  • lineNumbersStart: number → first visible line number (triggers view rebuild).
  • height / maxHeight: number | string | null → fixed height / max scroll height; reapplies sizing.
  • fade: boolean → enables/disables top/bottom fade shadows.
  • toolbarVisible: boolean → shows/hides the header toolbar.
  • ruler: boolean → shows/hides the column ruler.
  • rulerStyle: "full" | "tens" → ruler style.
  • rulerPosition: "top" | "bottom" → ruler placement.
  • download: boolean → enables the download action.
  • downloadContent: "view" | "raw" → which text to download.
  • filename: string → suggested download filename.
  • floatBar: boolean → shows/hides the floating control bar.
  • floatBarControls: string[] | CSV → which controls to show (same IDs as footerControls).
  • floatBarInFullscreen: boolean → keep it visible in fullscreen.
  • floatBarRemember: boolean → remember last position with localStorage.
  • playerAutoplay, playerLoop, playerButtons, playerProgress, playerShowNotes, playerWaitAfterActionMs, playerClosePopoverOnStop, playerStopHoldMs: (various types) → configure the step “player”.
  • showTokens: boolean → toggles token overlay.

Note


Also supported (stored as options, typically read at init or by specific methods):
footerControls, footerAlign, toastPosition, toastMax, copyToastMs, autoIndent, searchOffsetPx, fontSize, fontLineHeight, fontMin, fontMax, fontStep, typingCPS, autoFormatAfterTyped, fullscreen, compressed, markSpec, dedent, locale, translations.

Callback hooks onCopy | onSearch | onToggleHL | onFullscreen | onEdit.

These are honored where referenced in the codebase; some may not trigger immediate UI changes when set at runtime.

api.persistDataAttrs()
Writes a summary of the current options back to root.dataset (useful for SSR or external automation).
api.persistDataAttrs();

Events

api.on(type: string, handler: (ev: CustomEvent) => void)
api.off(type: string, handler: (ev: CustomEvent) => void)
Listen to changes such as search, toggleHL, fullscreen, player, floatbar, themechange, edit.
// Event hooks const offCopy = api.on?.('copy', ({detail})=>console.log('[ev] copy:', detail)); const offSearch = api.on?.('search', ({detail})=>console.log('[ev] search:', detail)); const offToggle = api.on?.('toggleHL', ({detail})=>console.log('[ev] toggleHL:', detail)); const offFull = api.on?.('fullscreen',({detail})=>console.log('[ev] fullscreen:', detail)); const offEdit = api.on?.('edit', ({detail})=>console.log('[ev] edit:', detail));

Accessibility

  • Keyboard friendly. You can move around with Tab/Shift+Tab. When you see a collapsed section (it shows “… lines collapsed”), select it and press Enter or Space to expand or collapse.
  • Clear labels. Buttons and controls are announced with meaningful names for screen readers.
  • Predictable focus. After collapsing, focus stays on the summary row; after expanding, focus returns to the header. Press Esc to close popovers and return focus to the button that opened them.
  • Readable at any size. Use the Zoom controls (A+/A–) or your browser zoom to increase text. Line numbers and the ruler can be shown or hidden from the view controls.
  • Reduced motion. If animations bother you, enable “Reduce motion” in your system settings—PWAxcode follows that preference.
  • Good contrast. Switch theme (Light/Dark, etc.) from the theme menu to improve readability.

Performance Tips

  • Working with very long files? Turn off “HL” (syntax highlighting) from the toolbar and re-enable it only when needed.
  • Collapse what you don’t need. Fold large sections to keep scrolling smooth.
  • Keep overlays light. Close popovers you’re not using and disable token/diagnostic overlays when they’re not necessary.
  • Zoom sensibly. Extremely large zoom levels can make big files feel slower; try a moderate zoom.
  • Search smoothly. Start a search, then use “Next/Previous” to move between results; wait for the page to settle before starting another search.
  • When in doubt, download. If your browser struggles with a huge file, download the text and open it in your desktop editor.

Troubleshooting

  • The floating toolbar doesn’t appear. Open the menu () and enable “Floating toolbar.” If you’re in fullscreen or “compressed” mode, exit it and try again. Make sure the page isn’t zoomed so far that the bar is off-screen—scroll a little to reveal it.
  • I can’t expand a collapsed section. Click the “… lines collapsed” row (or the caret in the gutter) and press Enter or Space. If it still won’t open, click once to select it and press Enter again. As a last resort, use “Unfold all” from the folding menu.
  • “Go to line” lands in the wrong place. If the target line is inside a collapsed block, the view scrolls to that block’s header first. Expand the block, then try “Go to line” again.
  • Downloaded file has the wrong name. Set a title at the top of the widget (if available) before downloading, or rename the file from your browser’s download shelf.
  • The ruler doesn’t show or won’t change style. Turn on “Ruler” from the view controls, then choose its style (“Tens” or “Full”) and position (“Top” or “Bottom”).
  • Popovers look out of place. Scroll the target into view and open the popover again. Very high zoom or narrow windows can push popovers off-screen; reduce zoom slightly or widen the window.
  • Fullscreen won’t start. Your browser or site may block fullscreen. Allow it if prompted, or try clicking the fullscreen button again after interacting with the page.
  • Copy to clipboard doesn’t work. Some browsers require a user gesture and a secure page (HTTPS). Use Ctrl/Cmd+C after selecting the text; on mobile, tap-and-hold then choose Copy.
  • Scrolling feels “stuck.” Check if a dialog or popover is open; press Esc to close it. If the page still won’t scroll, click inside the code area and try again.
  • Search finds nothing but the word is on the page. Check the search options (case sensitivity, whole-word, or regex) and try again. Clear previous highlights before starting a new search.
  • Highlight boxes look slightly misaligned. After changing font size or line wrapping, toggle wrap off/on or briefly resize the window to let overlays realign.
  • Line numbers start from an unexpected value. Look for the line-number settings in the view controls and reset the starting number to 1.