WLJS LogoWLJS Notebook

Notebooks

WLJS Notebook provides a rich API for programmatic manipulation of notebooks, cells, and windows compatible with Mathematica.

Programmatic notebook generation

You can create and manipulate notebooks programmatically using several core WL functions.

The API uses RemoteCellObj and RemoteNotebook objects to operate with cells and notebooks. We call them remote, since the evaluation kernel is generally isolated from the notebooks and in theory it is not necessary to run on the same physical machine, while all actual operations are performed by the host process of the app.

Creating notebooks

Use CreateDocument to create a new notebook populated with cells:

(* Create a notebook with text and a plot *)
nb = CreateDocument[{
  "Here is a plot example", 
  Plot[x, {x, 0, 1}]
}];

(* Create with specific cell styles *)
CreateDocument[{
  TextCell["My Section", "Section"], 
  ExpressionCell[Plot[x, {x,0,1}], "Input"]
}];

(* Create invisibly for background processing *)
nb = CreateDocument[{"Content"}, Visible -> False];

Use Defer to prevent evaluation:

CreateDocument[Defer[1 + 1]];
The notebook structure is flat. Nested cell groups will be automatically flattened

To save a created notebook to a file, use NotebookSave:

NotebookSave[nb, "path/to/notebook.wln"];

Cell Expressions

Here is a list of supported expressions in CreateDocument, CellPrint, NotebookWrite and CreateWindow:

  • Any expression → converted StandardForm input cell
  • _String → converted to text/markdown cell
  • ExpressionCell[expr_, "Input"]
  • ExpressionCell[expr_, "Output"] where expr will be converted to StandardForm
  • TextCell[expr_] represent text/markdown cells
  • TextCell[expr_, "Title"]
  • TextCell[expr_, "Section"]
  • TextCell[expr_, "Subsection"] represent styled markdown cells
  • Cell[expr_String, "Input"]
  • Cell[expr_String, "Output"] represents complete input and output cells
  • Cell[expr_String, "Input", subtype] represents complete output cell with a subtype, which sets a renderer for expr content:
    • "md" or "markdown" or "Markdown" will use markdown renderer,
    • "js" or "javascript" will treat expr as Javascript expression aka Javascript Cells,
    • "html" or "HTML" will render text content as HTML document,
    • "mermaid" or "Mermaid" will render text content as Mermaid diagram,
    • ...

The number of cell subtypes roughly corresponds to the number of available cell types in WLJS Notebook.

For example, let's create a document with HTML output cell:

CreateDocument[{
    Cell["<h2>Hello World</h2>", "Input", "html"],
    Cell["<h2>Hello World</h2>", "Output", "html"]
}]

Importing and opening notebooks

Use NotebookOpen to import a notebook:

(* Open a notebook by path *)
nb = NotebookOpen["path/to/notebook.wln"];

(* Open invisibly for background processing *)
nb = NotebookOpen["path/to/notebook.wln", Visible -> False];

or to show an imported one:

nb = NotebookOpen["path/to/notebook.wln", Visible -> False];

(* do something with a notebook *)

(* Open in a window *)
NotebookOpen[nb];

Accessing evaluation context

Use EvaluationNotebook to get a reference to the notebook where your code is running:

nb = EvaluationNotebook[];

EvaluationNotebook[] uses evaluation context to get the caller notebook object. It will not work correctly if called from a button click, timer or any other event:

Button[
    "Click", 
    (* context is lost ❌ *)
    Print[EvaluationNotebook[]]
] 

Notebook evaluation

To evaluate a notebook in the global context, use NotebookEvaluate

NotebookEvaluate["path/to/notebook.wln"]

This will evaluate all cells in the provided notebook using the same Kernel.

Cells manipulation

Creating cells

Use CellPrint to insert a new cell below the currently evaluated one:

(* Print an expression as output *)
cell = CellPrint[Plot[Sin[x], {x, 0, 2Pi}]];

(* Print with specific cell type *)
CellPrint[Cell["<h1>Hello World</h1>", "Output", "HTML"]];

(* Print a text cell *)
CellPrint[TextCell["This is a section", "Section"]];

To delete created cell, simply call NotebookDelete on cell:

NotebookDelete[cell];

Use NotebookWrite for more control over where cells are inserted:

(* Append to a notebook *)
nb = EvaluationNotebook[];
NotebookWrite[nb, Plot[x, {x, 0, 1}]];

(* Insert after a specific cell *)
NotebookWrite[NotebookLocationSpecifier[cell, "After"], expr];

(* Replace a specific cell *)
NotebookWrite[NotebookLocationSpecifier[cell, "On"], expr];

NotebookWrite returns a list of created cell objects or a single cell object.

Accessing evaluation context

Use EvaluationNotebook to get the notebook containing the currently evaluated cell:

nb = EvaluationNotebook[];

Here is an example where you can append a cell by clicking a button (which is not possible with CellPrint):

nb = EvaluationNotebook[];
Button["Create", NotebookWrite[nb, Style["Hi there!", Bold]]]

Use EvaluationCell to get a reference to the input cell that triggered the current evaluation:

cell = EvaluationCell[];

and add a cell after:

NotebookWrite[NotebookLocationSpecifier[cell, "After"], Red];

Use ResultCell to get a future reference to the output cell (even before it's created):

outputCell = ResultCell[];
ResultCell can be useful for tracking cell events or deleting it under certain conditions automatically

Use NotebookFocusedCell to get a focused / selected cell in the notebook:

focusedCell = NotebookFocusedCell[]

Alternatively, you can apply NotebookRead to get selected cells of a given notebook:

focusedCell = NotebookRead[EvaluationNotebook[]]

Writing to existing cells

Use NotebookWrite on cell objects to overwrite their content:

NotebookWrite[EvaluationCell[], "Hi there!"];

Here is another example with live updates:

cell = NotebookWrite[EvaluationNotebook[], Cell["Timer", "Input"]];
timer = SetInterval[NotebookWrite[cell, Now], 1000];
Button["Delete cell",
    TaskRemove[timer];
    NotebookDelete[cell];
]
Only input cells can be rewritten for now. Updating output cells is not possible unless you manually remove and create a new one

Reading cells

Use NotebookRead to read cell contents:

(* Read the focused cell *)
content = NotebookRead[NotebookFocusedCell[]];

List all cells

Use Cells to list all cell objects in the notebook

cells = Cells[];
Take[NotebookRead[cells], UpTo[5]]

Deleting cells

Use NotebookDelete to remove cells:

cell = CellPrint[Now];
(* Later... *)
NotebookDelete[cell];

Hidden input cells

You can create a pair of input-output cell with a hidden input one using CellOpen->False:

focused = NotebookFocusedCell[];
input = NotebookWrite[NotebookLocationSpecifier[focused, "After"], Cell["1+1", "Input", CellOpen->False]];
NotebookWrite[NotebookLocationSpecifier[input, "After"], Cell["2", "Output"]];

Cell event handlers

You can attach event handlers to cells to react to lifecycle events:

With[{cell = ResultCell[]},
  EventHandler[cell, {
    "Destroy" -> (Print["Cell was removed!"]&)
  }];

  "Delete me"
]

This can come in handy to remove listeners, stop timers, or other processes when you reevaluate the same cell.

Example: Self-destructing cell

With[{cell = EvaluationCell[]},
  EventHandler[InputButton["Delete me"], Function[Null,
    cell // NotebookDelete
  ]]
]

Expression windows manipulation

Note that created expression windows and cells in fact share the same object structure: RemoteCellObj

Creating windows

Use CreateWindow to open content in a new expression window:

(* Open graphics in a new window *)
win = CreateWindow[Graphics3D[Cuboid[]]];

(* With size and title *)
CreateWindow[Plot[Sin[x], {x, 0, 2Pi}, ImageSize->{300,300}], 
  WindowSize -> {400, 400}, 
  WindowTitle -> "My Plot"
];

(* HTML content *)
CreateWindow[Cell["<h2 style=\"color:red\">Hello</h2>", "Output", "HTML"]];

Closing windows

win = CreateWindow[Graphics3D[Sphere[]]];
Pause[3];
NotebookClose[win];

Create window from another window

CreateWindow[Button["Open", CreateWindow[Plot3D[x y, {x,-1,1}, {y,-1,1}]]]]

Tracking window events

You can attach event handlers to created windows:

state = "";
TextView[state // Offload, "Label" -> "State"]

win = CreateWindow[ExpressionCell[Plot[x, {x, 0, 1}], "Output"]];
EventHandler[win, {
  "Mounted" -> Function[Null, state = "Mounted"],
  "Closed" -> Function[Null, state = "Closed"]
}];

Application windows manipulation

Each visible window of WLJS Notebook can be retrieved from the context using CurrentWindow

appWindow = CurrentWindow[]

This returns WindowObj, that keeps socket connection to it.

If you refresh the page/window, the window object changes as well

The following rules apply:

  • Each opened application window has a unique WindowObj
  • Any function calls by UI events implicitly provide WindowObj as well, which can be accessed using CurrentWindow[]
  • Evaluation context also contains current WindowObj if the notebook is open
  • WindowObj is required for certain actions such as script execution on the window done by FrontSubmit and others

Tracking window events

You can attach event handlers to WindowObj:

state = "Open";
EventHandler[CurrentWindow[], {
    "Closed" -> Function[Null,
        state = "Closed";
    ]
}];
TextView[state // Offload]

Now try to reload a window or close/open a notebook—you will see the change in the state.

Cells as data storage

Programmatic control over the notebook structure allows you to reuse cells as storage for your data. For example, Cell representation automatically picks up a cell type if applicable. If you want to call a Python script from the session, where should you store .py expressions? Why not store them in another input cell and leave the name in the first line?

np.py
import numpy as np
new_array = np.linspace(0,10,11).astype('int');
new_array

Then we can locate this particular cell. Let's define a helper function:

getPythonCell[name_String] := StringDrop[SelectFirst[NotebookRead[Cells[]], MatchQ[Cell[_,_,name<>".py"]]][[1]], StringLength[name]+4]

and evaluate our script:

scriptText = getPythonCell["np"];
ExternalEvaluate["Python", scriptText];

Notebooks as modules

Use NotebookEvaluateAsModule to import notebooks as reusable modules:

{exports} = NotebookEvaluateAsModule["myLibrary.wln"];
NotebookEvaluateAsModule call breaks the evaluation order and may cause double evaluation of the caller cell. Please consider to use non-blocking NotebookEvaluateAsModuleAsync

The following rules apply:

  • Initialization cells are evaluated once per notebook object
  • The last Wolfram input cell is evaluated on every call and its result is exported
  • All other cells are ignored
  • Context of all global symbols will be completely isolated (lexically scoped)

Example 1: Creating a component library

Library.wln:

Initialization cell
.wlx
BigHeader[Text_String] := <h1><Text/></h1>;
Last cell (exports)
{BigHeader}

Main.wln:

{HeaderComponent} = NotebookEvaluateAsModule["Library.wln"];
.slide

<HeaderComponent>Hi there!</HeaderComponent>
This is my slide

For non-blocking imports, use NotebookEvaluateAsModuleAsync:

Then[NotebookEvaluateAsModuleAsync["Library.wln"], Function[exports,
  {HeaderComponent} = exports;
]];

Example 2: Creating a component library

Library.wln:

Initialization cell
w3D[x_,y_,t_] := Total@Table[With[{kx = 1.0 \[Omega], ky = 1.0 \[Omega]}, 
  Cos[ kx x + ky y - \[Omega] t]
], {\[Omega], 0, 3, 1.0}];

widget[] := Animate[Plot3D[w3D[x,y,t], {x,-Pi,Pi}, {y,-Pi,Pi}, MaxRecursion->0, Mesh->None, PlotRange->Full], {t,0,5}];
Last cell (exports)
widget

Main.wln:

animation = NotebookEvaluateAsModule["Library.wln"];
(* use it *)
animation[]

This approach may be more preferable for small modules than a traditional Wolfram Package:

  1. Easy to use, automatic context isolation
  2. All tests and examples are in the same notebook
  3. It allows to utilize non-standard cell types

Notebooks as templates

WLJS Notebook includes a template system for quickly creating new notebooks with predefined styles, content, and structure. Templates are accessible via the Command Palette or via File menu.

Template locations

LocationPath
User templates~/Documents/WLJS Notebooks/UserTemplates/
Built-in templatesAppExeFolder/app/wljs-packages/wljs-templates/Library/

How templates work

A template is simply a regular notebook. When you create a new notebook from a template:

  1. The notebook file is copied to your project directory
  2. If an attachments folder exists alongside the template, it is also copied
  3. The notebook opens with all cells and styles intact

The filename of the template notebook becomes the title shown in the template list.

Creating a custom template

Templates typically contain:

  • Style cells — HTML/CSS that override default notebook appearance
  • Banner or header content (optionally) — Images or formatted text or Javascript code
  • Hidden initialization cells - adds predefined symbols to the session
  • Boilerplate cells — Pre-written code or documentation structure
Enable Expert Mode from the settings menu to see hidden cells in notebook templates

Step 1: Create the notebook

Start with a new empty notebook and add your content.

Step 2: Add custom styles (optional)

Create an .html cell with CSS to customize the notebook appearance:

.html
<style>
  :root {
    --editor-key-keyword: #708;
    --editor-key-string: #a11;
  }
  
  body {
    background: #fafafa;
  }
  
  h1 {
    color: #5e8a8b;
  }
</style>

Evaluate the cell to apply the styles.

See Global Styling for a complete list of available CSS classes and variables.

Step 3: Hide style cells

For a clean template experience, you should hide the style cells using cell group properties:

  • Vanish — Makes the cell completely invisible and uneditable, but its output remains in the DOM (ideal for CSS/JS injection)

or

  • Lock + Hide — Keeps the output visible but prevents editing

Vanished cells can be viewed and edited in Expert mode (see Settings).

Step 4: Add hidden initialization cell (optional)

If you need to provide define some symbols:

  1. create a new cell at the top of the notebook;
  2. add the definitions;
  3. apply Vanish to this input cell.

Step 5: Add a banner (optional)

Create an .md cell with a banner image:

.md
<img src="/attachments/banner.png" style="width: 100%; height: 200px; object-fit: cover;"/>

Apply Lock and Hide properties of a cell group to keep the banner visible but uneditable.

Step 5: Add boilerplate cells

Create as many preformatted cells as you want

Step 6: Save and install

  1. Save your notebook
  2. Create a folder in ~/Documents/WLJS Notebooks/UserTemplates/ with a descriptive name
  3. Move your notebook (and attachments folder if any) into this folder
  4. Restart the app

Your template will now appear in the Command Palette under "New from Template".

Global Styling

You can apply custom CSS styles to all notebooks by adding them via Settings → Custom CSS. These styles are injected into the document head and apply globally.

Adding global styles

Settings
General
Custom CSS
Add your CSS rules
Restart app

The styles will be applied to all windows automatically.

Available CSS classes

WLJS Notebook exposes predefined CSS classes for styling various elements:

Document structure

SelectorDescription
bodyThe whole document
mainMain window container
.ccontainerCells container (extends to full size of main)
.cgroupA single group of cells: input + outputs + tools
.cframeInner group of cells: input + outputs
.cborderVertical line at the right side of cell group
.cwrapperInput/output cell wrapper
.cseparatorThin space between cells

Cell states and types

SelectorDescription
.cinitInitialization cells
.cinInput cells parent element
.coutOutput cells parent element
.ttintFocused cells
.cgi-icoInitialization cell group icon (teal dot)
#sidebar-rightRight sidebar in exported HTML

Input cell languages

SelectorDescription
.clang-genericUnknown cell type / language
.clang-markdownMarkdown cells
.clang-htmlHTML cells
.clang-wlxWLX cells
.clang-jsJavaScript cells
.clang-slideSlide cells

Wolfram Language input cells have an empty class field.

Markdown output

SelectorDescription
.cout.markdownMarkdown output cells
.markdown h1Heading level 1 in markdown
.markdown h2Heading level 2 in markdown
.markdown pParagraphs in markdown

Styling examples

Change notebook background

.ccontainer {
  background: lightblue;
}

body {
  background: lightblue !important;
}

main {
  background: lightblue !important;
}

Style the input cell border marker

The vertical line on the left side of input cells:

.cin > :nth-child(2)::after {
  border-color: #5e8a8b;
}

Custom heading colors

.markdown h1 {
  color: #2e7d32;
}

.markdown h2 {
  color: #1565c0;
}

Editor color variables

The following CSS variables control syntax highlighting and UI colors. Override them in :root:

:root {
  /* Syntax highlighting */
  --editor-key-meta: #404740;
  --editor-key-keyword: #708;
  --editor-key-atom: #219;
  --editor-key-literal: #164;
  --editor-key-string: #a11;
  --editor-key-escape: #e40;
  --editor-key-variable: #00f;
  --editor-local-variable: #30a;
  --editor-key-type: #085;
  --editor-key-class: #167;
  --editor-special-variable: #256;
  --editor-key-property: #00c;
  --editor-key-comment: #940;
  --editor-key-invalid: #f00;
  --editor-outline: #696969;
  
  /* Typography */
  font-size: medium;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 
    'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 
    'Open Sans', 'Helvetica Neue', sans-serif;
}

Global styles are also copied to exported standalone HTML files.

Notebooks as Mini Apps

Let's transform an interactive notebook to a mini app. We will parameterize this 3D plot and add export to an STL file:

Create our first cell and add it to initialization group

Initialization cell 1
model;
Model = Manipulate[model = RevolutionPlot3D[{Sin[t] +  Sin[y t] /m,
   Cos[t] +  Cos[x t] /m}, {t, 0, Pi},
  RegionFunction -> (Sin[5 (#4 + #5)] > 0 &), Mesh -> None,
  BoundaryStyle -> Black, PlotStyle -> Thickness[.1], MaxRecursion->1, Axes->False, ImageSize->400], {{x,5, "tX"}, 1, 10, 1}, {{y, 5, "tY"},1,10,1}, {{m,5.5,"Scale"},1,10,0.5}, Appearance->None, ContinuousAction->True];
All global variables we define in this notebook will be automatically scoped to it when we run it as a mini app. There is no need for context isolation

Now create another one, where we define an exporting function:

Initialization cell 2
export := Then[SystemDialogInputAsync["FileSave", {Null, {"STL" -> {"*.stl"}}}],
  Function[path,
    If[!StringQ[path], Return[]];
    Export[path, model];
  ]
]; 

Here we used SystemDialogInputAsync instead of SystemDialogInput, since the latter is blocking and cannot be used in calls generated by external asynchronous events such as button clicks.

Notebooks exported as mini apps use the very last cell's output as the main window. To take advantage of better customization, we use a WLX cell as the output instead of a plain Wolfram language cell:

Last cell in the notebook
.wlx

With[{
  ExportButton = Button["Export", export]
},
  <div class="bg-white p-4 w-full h-full">
    <div class="flex flex-row gap-x-2 justify-between">
      <Model/>
      <div class="mt-4"><ExportButton/></div>
    </div>
  </div>

]

You can try to evaluate this notebook and check the result.

To export it as a mini app, follow:

Call Share from the top menu or click the icon and choose Mini app:

Share
Mini app

Then double-click on the exported file to open it with WLJS as a runtime.

User dialogs

Use MessageDialog for notifications:

MessageDialog["Operation completed!"];
MessageDialog[Graphics[Disk[{0,0}, 1]]];

In the case of lost context, i.e. MessageDialog is called by a timer, button click - provide "Notebook" as an option:

n = EvaluationNotebook[];
Button["Message", MessageDialog["Operation completed!", "Notebook"->n]]

Use ChoiceDialog for user choices:

(* Simple OK/Cancel *)
result = ChoiceDialog["Proceed with operation?"];
(* Custom choices *)
choice = ChoiceDialog["Select option:", {
  "Option A" -> "a",
  "Option B" -> "b"
}];

ChoiceDialog is a blocking function. Avoid using it in timers like SetTimeout, external event handlers such as InputButton or Button, or within AsyncFunction. Use ChoiceDialogAsync instead:

n = EvaluationNotebook[];
Button["Message", Then[ChoiceDialogAsync["Proceed with operation?", "Notebook"->n], Function[choise,
  Print[choise];
]]]

Use Input or InputString for user input:

Input["Enter expression:", x^2]
InputString["Enter your name:"]

Both of them are blocking functions. Again, use async versions in Button and other event handlers:

nb = EvaluationNotebook[];
Button["Enter expr", Then[InputAsync["Enter expression:", x^2, "Notebook"->nb],
  Function[expr,
    NotebookWrite[nb, expr];
  ]
]]

System File dialogs

This requires WLJS desktop application

Use SystemDialogInput for file operations:

(* Open file *)
file = SystemDialogInput["FileOpen", {Null, {
  "Images" -> {"*.png", "*.jpg"},
  "All Files" -> {"*.*"}
}}];

(* Save file *)
path = SystemDialogInput["FileSave"];

(* Select directory *)
dir = SystemDialogInput["Directory"];

System dialogs are no longer associated with notebooks; instead they require WindowObj to be provided, which specifies the parent application window:

w = CurrentWindow[];
SetTimeout[Then[SystemDialogInputAsync["FileSave", "Window"->w], Print], 1000];

However, you do not have to provide "Window" if the dialog is called from a button click. The event context carries "Window" implicitly:

Button["Save", Then[SystemDialogInputAsync["FileSave"], Print]]

Editor commands

You can send direct commands to the cells editor using FrontEditorSelected. This function is defined only on frontend, i.e. it has to be executed using FrontSubmit or FrontFetch.

To read the last selected text in a cell:

FrontFetch[FrontEditorSelected["Get"]]
FrontFetch is a blocking function, please, consider FrontFetchAsync

Or using a button:

Button["Read selected", Then[FrontFetchAsync[FrontEditorSelected["Get"]], Print]]

Read cursor position:

Button["Read selected", Then[FrontFetchAsync[FrontEditorSelected["Cursor"]], Print]]

To insert or overwrite:

Button["Overwrite", FrontSubmit[FrontEditorSelected["Set", "1+1"]] ]

Clipboard

Copying to clipboard

Use CopyToClipboard to programmatically copy:

CopyToClipboard[{1, 2, 3, 4, 5}];

In the case of context loss, provide "Window" object as an option, i.e.

win = CurrentWindow[];
SetTimeout[CopyToClipboard[RandomWord[], "Window"->win]; Echo["Copied"], 1000];

Use ClickToCopy for interactive copy buttons:

ClickToCopy["Click to copy this text"]
ClickToCopy["Copy Code", "Plot[Sin[x], {x, 0, 2Pi}]"]

Pasting from clipboard

Use Paste to paste clipboard content as a new cell:

Paste[];

Use PasteButton for interactive paste buttons:

PasteButton["Paste"]

Directly read clipboard

ReadClipboard is symbol is defined on the frontend and allows to directly read clipboard from a given window. Since this is a frontend-only function, you need to use FrontFetch or FrontFetchAsync:

FrontFetch[ReadClipboard[]]

or by a click on a button:

Button["Read", Then[FrontFetchAsync[ReadClipboard[]], Print]]
Note, that events generated by button clicks or other UI interactions provide "Window" object to FrontFetchAsync implicitly. This will not work automatically for timers, i.e. SetTimeout or events generated by parallel kernels

Notebook storage

Use NotebookStore to persist data within a notebook. This data survives export/import cycles, including Static HTML export.

NotebookStore[key_String ]

this object represents a data stored with key in the notebook. Or excplicitly specify the notebook:

NotebookStore[nb, key_String ]

Writting data

NotebookWrite[NotebookStore["myKey"], {1, 2, 3, 4, 5}];
NotebookWrite[NotebookStore["settings"], <|"theme" -> "dark", "fontSize" -> 14|>];

Reading data

data = NotebookRead[NotebookStore["myKey"]];

Note, that NotebookRead is a blocking function; use NotebookReadAsync if you need to read out the data by a timer or user actions.

Notebooks as command palette tools

We already mentioned our command palette in the very first guide. Every tool is a normal notebook, which is evaluated in the background and manipulates your working notebook, creating temporal cells whenever you call it from the palette.

User's utilities are stored in ~/Documents/WLJS Notebooks/User palette/

What you should note before starting:

  1. Initialization cells are evaluated once
  2. All other cells are evaluated every time you call a tool (except text/markdown cells)
  3. All "global" symbols in tool notebook will be contextually isolated
  4. CurrentWindow will return the window of the host notebook (not tool's notebook!)
  5. NotebookDirectory, NotebookWrite, NotebookRead, NotebookFocusedCell, EvaluationNotebook will be in the context of the host notebook (not tool's notebook!)
  6. Directory[] will return the directory of tool's notebook (not host!)
  7. Icon can be set using a specially tagged WLX cell (see examples)
  8. Title of the tool has to be in the first markdown cell of the tool's notebook
  9. You do not need to evaluate any of cells in the tool's notebook

All manipulations on the notebook's data can be performed using all symbols we discussed in all sections of this guide.

Example-1: search text in a cell and print results

In this example we prompt a user to enter a string, then read the content of focused cell, find all matches and print them in the output cell.

First cell - tool name:

.md
# Search in cell
This tool finds a string in a focused cell and prints the results 

This example does not require any initialization cells, then we can skip this part and define our "action" cell:

focused = NotebookFocusedCell[];
content = NotebookRead[focused][[1]];
Then[InputStringAsync["Enter a string to search"], Function[string,
  If[!TrueQ[StringLength[string] > 3], EchoLabel["Warning"]["String is too short"],
    With[{cases = StringCases[content, (WordCharacter..|"")~~string~~(WordCharacter..|""), 
IgnoreCase->True]},
      NotebookWrite[NotebookLocationSpecifier[focused, "After"], ExpressionCell[TableForm[cases], "Output"]]
    ]
]]];

As the last thing, we make a nice icon. This is a specially tagged WLX cell:

icon.wlx
Component[OptionsPattern[]] := With[{Title = OptionValue["Title"], Kbd = OptionValue["Shortcut"], UTag = OptionValue["Tag"], Btn = OptionValue["Button"]},
    <li tabindex="-1" tag="{UTag}" class="list-none nooline group flex cursor-default select-none items-center rounded-md px-2 py-1 focus:bg-teal-500/25">
             <svg class="h-4 ml-1  w-4 flex-none text-gray-900  dark:text-gray-400 text-opacity-40" fill="none" viewBox="0 0 24 24"><path d="M21 4H3M20 8H6M18 12H9M15 16H8M17 20H12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> 
              <span class="ml-3 flex-auto truncate"><Title/></span><span class="ml-3 flex-none text-xs font-semibold text-gray-500">
                <kbd class="font-sans"><Kbd/></kbd>
                <button class="p-0.5 rounded hover:bg-gray-100 dark:hover:bg-gray-200" btag="{Btn}">
                  <svg class="w-4 h-4 text-gray-400" viewBox="0 0 24 24" fill="none">
                    
                    <path fill-rule="evenodd" clip-rule="evenodd" d="M12 2.75C6.89137 2.75 2.75 6.89137 2.75 12C2.75 17.1086 6.89137 21.25 12 21.25C17.1086 21.25 21.25 17.1086 21.25 12C21.25 6.89137 17.1086 2.75 12 2.75ZM1.25 12C1.25 6.06294 6.06294 1.25 12 1.25C17.9371 1.25 22.75 6.06294 22.75 12C22.75 17.9371 17.9371 22.75 12 22.75C6.06294 22.75 1.25 17.9371 1.25 12ZM12 7.75C11.3787 7.75 10.875 8.25368 10.875 8.875C10.875 9.28921 10.5392 9.625 10.125 9.625C9.71079 9.625 9.375 9.28921 9.375 8.875C9.375 7.42525 10.5503 6.25 12 6.25C13.4497 6.25 14.625 7.42525 14.625 8.875C14.625 9.83834 14.1056 10.6796 13.3353 11.1354C13.1385 11.2518 12.9761 11.3789 12.8703 11.5036C12.7675 11.6246 12.75 11.7036 12.75 11.75V13C12.75 13.4142 12.4142 13.75 12 13.75C11.5858 13.75 11.25 13.4142 11.25 13V11.75C11.25 11.2441 11.4715 10.8336 11.7266 10.533C11.9786 10.236 12.2929 10.0092 12.5715 9.84439C12.9044 9.64739 13.125 9.28655 13.125 8.875C13.125 8.25368 12.6213 7.75 12 7.75ZM12 17C12.5523 17 13 16.5523 13 16C13 15.4477 12.5523 15 12 15C11.4477 15 11 15.4477 11 16C11 16.5523 11.4477 17 12 17Z" fill="currentColor"/>
                  </svg>                  
                </button>
              </span>
    </li>    
];

Options[Component] = {"Title"->"Example", "Shortcut"->"", "Tag"->"generic", "Button"->Null};

Component

If you are looking for some nice icons, visit the SVGRepo website. In this example it uses 2 SVG icons, one for a tool and another one for a question mark.

Now we save this notebook to the directory ~/Documents/WLJS Notebooks/User palette/ and restart the WLJS application.

On this page