diff --git a/znai-docs/znai/llm.txt b/znai-docs/znai/llm.txt
index 9deadeda6..c676d668d 100644
--- a/znai-docs/znai/llm.txt
+++ b/znai-docs/znai/llm.txt
@@ -146,8 +146,8 @@ answer-link: znai-from-export/introduction/getting-started#command-line
## CLI download
Download and unzip
-[znai](https://repo.maven.apache.org/maven2/org/testingisdocumenting/znai/znai-dist/1.92-SNAPSHOT/znai-dist-1.92-SNAPSHOT-znai.zip).
-Add it to your `PATH`.
+[znai](https://repo.maven.apache.org/maven2/org/testingisdocumenting/znai/znai-dist/1.92/znai-dist-1.92-znai.zip). Add
+it to your `PATH`.
## Brew
@@ -162,7 +162,7 @@ answer-link: znai-from-export/introduction/getting-started#maven-plugin
org.testingisdocumenting.znaiznai-maven-plugin
- 1.92-SNAPSHOT
+ 1.92
```
@@ -830,6 +830,9 @@ Title match during search yields the highest score.
For example this current section full title is: *Flow Search Local*.
+Queries with special characters like `List.map` or `c++` are additionally matched verbatim: sections containing the
+exact text appear first. Wrap a query in quotes, e.g. `"List.map"`, to only match sections containing the exact text.
+
As your documentation grows, keep checking how easy it is to navigate to a section of your documentation using `/`.
Avoid: using generic names in your page titles and page section titles. You should not have dozens of pages called
@@ -910,7 +913,7 @@ To define a footnote use
To add a reference to the footnote use `[^my-id]` which will result in [^my-id]
-[^my-id]: extra content for my footnote goes here potentially including code blocks Constructor
+[^my-id]: extra content for my footnote goes here potentially including code blocks Constructor()
Note: numeric footnotes are treated as text footnotes, and they will be assigned the auto incremented number in order of
appearance.
@@ -938,7 +941,7 @@ answer-link: znai-from-export/flow/footnotes#footnotes-list
A footnotes list is automatically appended at the end of the page when footnotes are present. Clicking the number in the
list navigates back to the reference [^another-note].
-[^another-note]: This is another footnote to demonstrate the list with multiple entries
+[^another-note]: This is another footnote to demonstrate the list with multiple entries.
To hide the footnotes list, set `hideFootnoteList` to `true` in `meta.json`:
@@ -2247,6 +2250,11 @@ score, Integer, another description line with *markdown* support
```
```
+```api-parameters
+firstName, String, description with markdown support
+score, Integer, another description line with markdown support
+```
+
# Snippets :: API Parameters :: Nested
answer-link: znai-from-export/snippets/api-parameters#nested
@@ -2266,6 +2274,15 @@ roles.description, String, role description
Note: when using this approach it is necessary to explicitly define a `root` entry, such as `person` in this example.
+```api-parameters
+sessionId, Integer, session Id
+person, Person, person to login with
+person.firstName, String, first name of the person
+person.lastName, String, last name of the person
+roles, List, list of authorized roles
+roles.id, String, role id
+roles.description, String, role description
+```
Note: if a parameter name actually contains a period ("."), you can prevent this nesting behavior by putting the
parameter name in single quotes, e.g. "person.firstName"
@@ -2282,6 +2299,11 @@ score, Integer, another description line with *markdown* support
```
```
+```api-parameters
+firstName, String, description with markdown support
+score, Integer, another description line with markdown support
+```
+
# Snippets :: API Parameters :: Collapsing Parameters
answer-link: znai-from-export/snippets/api-parameters#collapsing-parameters
@@ -2294,6 +2316,10 @@ zipCode, String, zip code
```
```
+```api-parameters
+city, String, city name
+zipCode, String, zip code
+```
Note: `collapsed` requires `title` to be present
@@ -2314,6 +2340,16 @@ zipCode, String, zip code
```
```
+```api-parameters
+firstName, String, description with markdown support
+score, Integer, another description line with markdown support
+```
+
+```api-parameters
+city, String, city name
+zipCode, String, zip code
+```
+
# Snippets :: API Parameters :: Size
answer-link: znai-from-export/snippets/api-parameters#size
@@ -2326,6 +2362,11 @@ score, Integer, another description line with *markdown* support
```
```
+```api-parameters
+firstName, String, description with markdown support
+score, Integer, another description line with markdown support
+```
+
# Snippets :: API Parameters :: Multi-line CSV Description
answer-link: znai-from-export/snippets/api-parameters#multi-line-csv-description
@@ -2350,6 +2391,10 @@ Specify whether to use gpu
`````
```
+```api-parameters
+cores, String, Specify how many cores to allocate for execution execute(cores: 10)
+gpu, Boolean, "Specify whether to use gpu execute(cores: 10, gpu: true)"
+```
Note: Use larger number of backticks on outside then inside to distinct between `api-parameters` plugin boundaries and
nested code blocks
@@ -2415,6 +2460,15 @@ Given the above file, use
to display it as API Parameters
+```api-parameters
+sessionId, Integer, session Id
+person, Person, person to login with
+person.firstName, String, first name of the person
+person.lastName, String, last name of the person
+roles, List, list of authorized roles
+roles.id, String, role id
+roles.description, String, role description
+```
Note: `description` field in JSON file is treated as Markdown
@@ -2431,6 +2485,10 @@ score, Integer, another description line with *markdown* support
```
```
+```api-parameters
+firstName, String, description with markdown support
+score, Integer, another description line with markdown support
+```
In the example above `customPrefix` is added to each parameter link.
@@ -2439,6 +2497,10 @@ answer-link: znai-from-export/snippets/api-parameters#long-parameter-names
Znai hard wraps long parameter names to leave more space to description.
+```api-parameters
+VERY_LONG_PARAMETER_NAME_WITHOUT_SPACES, String, description with markdown support
+VERY_LONG_ANOTHER_PARAMETER_NAME_WITHOUT_SPACES, String, another description line with markdown support
+```
Use `noWrap: true` to remove hard wrap enforcement
@@ -2449,6 +2511,11 @@ VERY_LONG_ANOTHER_PARAMETER_NAME_WITHOUT_SPACES, String, another description lin
```
```
+```api-parameters
+VERY_LONG_PARAMETER_NAME_WITHOUT_SPACES, String, description with markdown support
+VERY_LONG_ANOTHER_PARAMETER_NAME_WITHOUT_SPACES, String, another description line with markdown support
+```
+
# Snippets :: API Parameters :: Wide Mode
answer-link: znai-from-export/snippets/api-parameters#wide-mode
@@ -2462,6 +2529,11 @@ line with *markdown* support and few moe lines"
```
```
+```api-parameters
+VERY_LONG_PARAMETER_NAME_WITHOUT_SPACES, String, "longer line longer line, description with markdown support"
+VERY_LONG_ANOTHER_PARAMETER_NAME_WITHOUT_SPACES, String, "longer line longer line, another description line with markdown support and few moe lines"
+```
+
# Snippets :: Code References :: Local References
answer-link: znai-from-export/snippets/code-references#local-references
@@ -3854,6 +3926,10 @@ extract description of methods and convert parameters into [API Parameters](snip
:include-doxygen-doc-params: utils::nested::my_func { title: "My Params" }
```
+```api-parameters
+first_param, int, description of first param item a item b
+second_param, bool, description of second param
+```
Head over to [CPP Description Extraction](CPP/description-extraction) to learn more
@@ -3867,8 +3943,15 @@ Znai provides plugins to automatically create reference documentation for method
```
+```api-parameters
+v1, const T1 &, value to print
+v2, const T2 &, value to print
+```
-
+```api-parameters
+T1, , type of the value one to print
+T2, , type of the value two to print
+```
```hpp
@@ -6410,13 +6493,51 @@ Note: Requires `title` to be set.
}
```
+# Visuals :: Iframe :: Collapse
+answer-link: znai-from-export/visuals/iframe#collapse
+
+Use `collapsed: true|false` to make iframe collapsible.
+
+Note: Requires `title` to be set.
+
+```markdown
+:include-iframe: iframe/custom.html {
+ title: "collapsible content",
+ fit: true,
+ collapsed: true
+}
+```
+
+# Visuals :: Iframe :: No Gap
+answer-link: znai-from-export/visuals/iframe#no-gap
+
+Use `noGap: true` to remove top/bottom margins when there are multiple iframes in a row. Use `noGapBorder: true` to add
+a delimiter between them:
+
+```markdown
+:include-iframe: iframe/custom.html {
+ title: "part one",
+ fit: true,
+ noGap: true,
+ noGapBorder: true
+}
+
+:include-iframe: iframe/custom.html {
+ title: "part two",
+ fit: true
+}
+```
+
# Visuals :: Iframe :: Embedding Video
answer-link: znai-from-export/visuals/iframe#embedding-video
Use `include-iframe` to embed media from other places. By default, aspect ratio is set to `16:9`.
-```
-:include-iframe: https://www.youtube.com/embed/tgbNymZ7vqY
+```markdown
+:include-iframe: https://www.youtube.com/embed/tgbNymZ7vqY {
+ title: "sample video",
+ newTabEnabled: true
+}
```
# Visuals :: Iframe :: Aspect Ratio
@@ -8280,9 +8401,18 @@ Use `include-doxygen-doc-params` to extract parameters description from doxygen
:include-doxygen-doc-params: utils::nested::my_func { title: "My Params" }
```
+```api-parameters
+first_param, int, description of first param item a item b
+second_param, bool, description of second param
+```
Use `small: true` option to make parameters smaller
+```api-parameters
+first_param, int, description of first param item a item b
+second_param, bool, description of second param
+```
+
# CPP :: Description Extraction :: Extract Parameters By Args
answer-link: znai-from-export/CPP/description-extraction#extract-parameters-by-args
@@ -8292,6 +8422,10 @@ Use `args` to select a specific overload by providing parameters string
:include-doxygen-doc-params: utils::nested::my_func { title: "My Params", args: "int" }
```
+```api-parameters
+first_param, int, description of first param item a item b
+```
+
# CPP :: Description Extraction :: Extract Template Parameters
answer-link: znai-from-export/CPP/description-extraction#extract-template-parameters
@@ -8315,6 +8449,11 @@ void multi_println(const T1& v1, const T2& v2) {
:include-doxygen-doc-params: multi_println { title: "Template parameters", type: "template" }
```
+```api-parameters
+T1, , type of the value one to print
+T2, , type of the value two to print
+```
+
# CPP :: Description Extraction :: Ignore Template Parameters
answer-link: znai-from-export/CPP/description-extraction#ignore-template-parameters
@@ -8360,6 +8499,12 @@ int add(int a, int b);
:include-doxygen-doc-params: math::add
```
+```api-parameters
+return, , sum of two numbers
+a, int, number to add to
+b, int, number that is added
+```
+
# CPP :: Auto Reference :: Member Signature, Comment And Parameters
answer-link: znai-from-export/CPP/auto-reference#member-signature-comment-and-parameters
@@ -8405,7 +8550,10 @@ void free_func() {
```
-
+```api-parameters
+first_param, int, description of first param item a item b
+second_param, bool, description of second param
+```
```markdown
@@ -8426,6 +8574,17 @@ void multi_println(const T1& v1, const T2& v2) {
}
```
+
+```api-parameters
+v1, const T1 &, value to print
+v2, const T2 &, value to print
+```
+
+```api-parameters
+T1, , type of the value one to print
+T2, , type of the value two to print
+```
+
# CPP :: Auto Reference :: Member Signature Only
answer-link: znai-from-export/CPP/auto-reference#member-signature-only
@@ -8508,7 +8667,10 @@ Use `args` to select a specific overload by providing parameters string
```
-
+```api-parameters
+param1, long, description of param1
+param3, bool, description of param3
+```
Note: Args are coma and spaces sensitive. Znai will print available args variants in case of mismatch for you to copy
@@ -8539,19 +8701,28 @@ Use `include-doxygen-compound` to render a definition of a class/struct
#### sing
-
+```api-parameters
+tone, int, tone at which to sing
+volume, int, volume at which to sing
+```
#### bark
-
+```api-parameters
+myClass, const MyClass &, to test reference
+tone, int, tone at which to sing
+volume, int, volume at which to sing
+```
#### smile
-
+```api-parameters
+volume, int, smile volume
+```
#### number_of_sounds
@@ -8564,6 +8735,12 @@ Use `include-doxygen-compound` to render a definition of a class/struct
#### help
+
+```api-parameters
+tone, int, tone at which to sing
+volume, int, volume at which to sing
+```
+
# CPP :: Auto Reference :: Cross-Reference
answer-link: znai-from-export/CPP/auto-reference#cross-reference
diff --git a/znai-docs/znai/release-notes/1.93/add-2026-08-31-checkboxes-interactive-checklist.md b/znai-docs/znai/release-notes/1.93/add-2026-08-31-checkboxes-interactive-checklist.md
new file mode 100644
index 000000000..42c752fb1
--- /dev/null
+++ b/znai-docs/znai/release-notes/1.93/add-2026-08-31-checkboxes-interactive-checklist.md
@@ -0,0 +1 @@
+* Add: [checkboxes](visuals/checkboxes) fence plugin renders bullet points as an interactive checklist, checked state persists in browser local storage
diff --git a/znai-docs/znai/release-notes/2026.md b/znai-docs/znai/release-notes/2026.md
index 524f4030d..7950dea5d 100644
--- a/znai-docs/znai/release-notes/2026.md
+++ b/znai-docs/znai/release-notes/2026.md
@@ -1,3 +1,7 @@
+# 1.93
+
+:include-markdowns: 1.93
+
# 1.92
:include-markdowns: 1.92
diff --git a/znai-docs/znai/toc b/znai-docs/znai/toc
index 1876ece96..e6635fedd 100644
--- a/znai-docs/znai/toc
+++ b/znai-docs/znai/toc
@@ -42,6 +42,7 @@ visuals
images
image-annotations
cards
+ checkboxes
charts
mermaid-diagrams
SVG
diff --git a/znai-docs/znai/visuals/checkboxes.md b/znai-docs/znai/visuals/checkboxes.md
new file mode 100644
index 000000000..014d3c015
--- /dev/null
+++ b/znai-docs/znai/visuals/checkboxes.md
@@ -0,0 +1,62 @@
+# Interactive Checklist
+
+To render an interactive checklist use the `checkboxes` fence plugin.
+Each bullet point inside becomes a checkbox users can tick.
+
+ ```checkboxes
+ * install cli
+ * setup environment
+ * run first example
+ ```
+
+```checkboxes
+* install cli
+* setup environment
+* run first example
+```
+
+Note: Checked state is persisted in the browser local storage, so it survives page reloads and revisits.
+Changing checklist content resets its checked state. During local preview state is not persisted.
+
+# Complex Content
+
+Bullet points can contain any markdown, including multiple paragraphs and code snippets.
+
+ ````checkboxes
+ * install dependencies using package manager
+
+ ```bash
+ npm install --save-dev my-tool
+ ```
+
+ * validate generated config
+
+ ```javascript
+ module.exports = {
+ preset: "default",
+ };
+ ```
+
+ * commit changes
+ ````
+
+````checkboxes
+* install dependencies using package manager
+
+ ```bash
+ npm install --save-dev my-tool
+ ```
+
+* validate generated config
+
+ ```javascript
+ module.exports = {
+ preset: "default",
+ };
+ ```
+
+* commit changes
+````
+
+Note: Four backticks were used instead of the usual three. This is done so one fence block can include
+another block (code snippet) without confusion. It can be any number of backticks greater than three.
diff --git a/znai-reactjs/src/App.css b/znai-reactjs/src/App.css
index 572d06247..1482f3b04 100644
--- a/znai-reactjs/src/App.css
+++ b/znai-reactjs/src/App.css
@@ -82,6 +82,9 @@
--znai-card-shadow: 0 2px 2px 0 rgb(0 0 0 / 15%), 0 3px 1px -2px rgb(0 0 0 / 13%), 0 1px 5px 0 rgb(0 0 0 / 22%);
--znai-card-link-separator-color: var(--znai-snippets-outer-border-color);
+ --znai-checkboxes-border-color: #b0b0b0;
+ --znai-checkboxes-checked-color: var(--znai-brand-primary-color);
+
--znai-space-above-next-prev-navigation: 150px;
--znai-space-below-next-prev-navigation: 100px;
--znai-space-left-next-prev-navigation: 50px;
diff --git a/znai-reactjs/src/App.jsx b/znai-reactjs/src/App.jsx
index 0bbe24cc2..d2fc37498 100644
--- a/znai-reactjs/src/App.jsx
+++ b/znai-reactjs/src/App.jsx
@@ -101,6 +101,7 @@ import { attentionBlockDemo } from "./doc-elements/paragraph/AttentionBlock.demo
import { attentionBlockPresentationDemo } from "./doc-elements/paragraph/PresentationAttentionBlock.demo";
import { containerTitleDemo } from "./doc-elements/container/ContainerTitle.demo";
import { cardsDemo } from "./doc-elements/card/CardsDemo";
+import { checkboxesDemo } from "./doc-elements/checkboxes/Checkboxes.demo";
import { doxygenPresentationDemo } from "./doc-elements/doxygen/PresentationDoxygen.demo";
import { jsonPresentationDemo } from "./doc-elements/json/PresentationJson.demo";
import { footnoteDemo } from "./doc-elements/footnote/Footnote.demo";
@@ -190,6 +191,7 @@ registries
.registerAsGrid("SVG", 0, svgDemo)
.registerAsGrid("GraphViz SVG", 0, graphVizSvgDemo)
.registerAsRows("Cards", cardsDemo)
+ .registerAsRows("Checkboxes", checkboxesDemo)
.registerAsRows("Diagram Legend", diagramLegendDemo)
.registerAsGrid("Keyboard shortcuts", 0, keyboardShortcutsDemo)
.registerAsGrid("Iframe", 0, iframeDemo)
diff --git a/znai-reactjs/src/doc-elements/DefaultElementsLibrary.jsx b/znai-reactjs/src/doc-elements/DefaultElementsLibrary.jsx
index 8df429fd1..2b157bcd5 100644
--- a/znai-reactjs/src/doc-elements/DefaultElementsLibrary.jsx
+++ b/znai-reactjs/src/doc-elements/DefaultElementsLibrary.jsx
@@ -89,6 +89,7 @@ import { PythonMethod } from "./python/PythonMethod";
import { ApiLinkedTextBlock } from "./api/ApiLinkedTextBlock";
import { OpenApiMethodAndUrl } from "./open-api/OpenApiMethodAndUrl";
import { Card } from "./card/Card";
+import { Checkboxes } from "./checkboxes/Checkboxes";
import { FootnoteReference } from "./footnote/FootnoteReference";
import { FootnoteBackLinks } from "./footnote/FootnotesList";
import { EmbeddedHtml } from "./html/EmbeddedHtml";
@@ -183,6 +184,7 @@ presentationElementHandlers.AnnotatedImage = presentationAnnotatedImageHandler
library.AnnotatedImageWithOrderedList = AnnotatedImageWithOrderedList
library.Card = Card;
+library.Checkboxes = Checkboxes;
library.FootnoteReference = FootnoteReference;
library.FootnoteBackLinks = FootnoteBackLinks;
diff --git a/znai-reactjs/src/doc-elements/checkboxes/Checkboxes.css b/znai-reactjs/src/doc-elements/checkboxes/Checkboxes.css
new file mode 100644
index 000000000..689873f77
--- /dev/null
+++ b/znai-reactjs/src/doc-elements/checkboxes/Checkboxes.css
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2026 znai maintainers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.znai-checkboxes {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ margin-bottom: 15px;
+}
+
+.znai-checkboxes-item {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+}
+
+/* 1lh keeps the checkbox centered against the first line of the item content */
+.znai-checkboxes-tick-cell {
+ display: flex;
+ align-items: center;
+ height: 1lh;
+ flex-shrink: 0;
+}
+
+.znai-checkboxes-tick {
+ appearance: none;
+ width: 16px;
+ height: 16px;
+ margin: 0;
+ border: 2px solid var(--znai-checkboxes-border-color);
+ border-radius: 4px;
+ background-color: transparent;
+ cursor: pointer;
+}
+
+.znai-checkboxes-tick:hover {
+ border-color: var(--znai-checkboxes-checked-color);
+}
+
+.znai-checkboxes-tick:focus-visible {
+ outline: 2px solid var(--znai-checkboxes-checked-color);
+ outline-offset: 2px;
+}
+
+.znai-checkboxes-tick:checked {
+ border-color: var(--znai-checkboxes-checked-color);
+ background-color: var(--znai-checkboxes-checked-color);
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E");
+ background-size: 12px 12px;
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.znai-checkboxes-item-content {
+ flex: 1;
+ min-width: 0;
+ transition: opacity 0.15s ease-in-out;
+
+ --znai-single-column-render-width: auto;
+}
+
+.znai-checkboxes-item.checked .znai-checkboxes-item-content {
+ opacity: 0.55;
+}
diff --git a/znai-reactjs/src/doc-elements/checkboxes/Checkboxes.demo.tsx b/znai-reactjs/src/doc-elements/checkboxes/Checkboxes.demo.tsx
new file mode 100644
index 000000000..e109cbe68
--- /dev/null
+++ b/znai-reactjs/src/doc-elements/checkboxes/Checkboxes.demo.tsx
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2026 znai maintainers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from "react";
+
+import { Registry } from "react-component-viewer";
+import { elementsLibrary } from "../DefaultElementsLibrary";
+import { Checkboxes } from "./Checkboxes";
+
+export function checkboxesDemo(registry: Registry) {
+ registry
+ .add("one liners", () => (
+
+ ))
+ .add("long wrapped text", () => (
+
+ ))
+ .add("with code snippet", () => (
+
+ ));
+}
+
+function oneLiners() {
+ return [
+ {
+ id: "install-cli",
+ content: [paragraph("install cli")],
+ },
+ {
+ id: "setup-environment",
+ content: [paragraph("setup environment")],
+ },
+ {
+ id: "run-first-example",
+ content: [paragraph("run first example")],
+ },
+ ];
+}
+
+function longText() {
+ const longLine =
+ "review the deployment guide and make sure all the required services are provisioned, " +
+ "credentials are stored in the secrets manager, and the monitoring dashboards are configured " +
+ "for every environment including staging and production";
+
+ return [
+ {
+ id: "review-deployment-guide",
+ content: [paragraph(longLine)],
+ },
+ {
+ id: "short-follow-up",
+ content: [paragraph("short follow up")],
+ },
+ ];
+}
+
+function withSnippet() {
+ return [
+ {
+ id: "install-dependencies",
+ content: [
+ paragraph("install dependencies using package manager"),
+ {
+ type: "Snippet",
+ lang: "bash",
+ snippet: "npm install --save-dev my-tool\nnpm run my-tool -- --init\n",
+ },
+ ],
+ },
+ {
+ id: "validate-config",
+ content: [
+ paragraph("validate generated config"),
+ {
+ type: "Snippet",
+ lang: "javascript",
+ snippet: 'module.exports = {\n preset: "default",\n output: "./build",\n};\n',
+ },
+ ],
+ },
+ {
+ id: "commit-changes",
+ content: [paragraph("commit changes")],
+ },
+ ];
+}
+
+function paragraph(text: string) {
+ return {
+ type: "Paragraph",
+ content: [
+ {
+ text,
+ type: "SimpleText",
+ },
+ ],
+ };
+}
diff --git a/znai-reactjs/src/doc-elements/checkboxes/Checkboxes.tsx b/znai-reactjs/src/doc-elements/checkboxes/Checkboxes.tsx
new file mode 100644
index 000000000..80d46397d
--- /dev/null
+++ b/znai-reactjs/src/doc-elements/checkboxes/Checkboxes.tsx
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2026 znai maintainers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { useState } from "react";
+
+import { DocElementContent, WithElementsLibrary } from "../default-elements/DocElement";
+import { currentPageIdWithDocId } from "../../structure/DocumentationNavigation";
+import { isPreviewEnabled } from "../../structure/docMeta";
+
+import "./Checkboxes.css";
+
+interface CheckboxItem {
+ id: string;
+ content: DocElementContent;
+}
+
+interface Props extends WithElementsLibrary {
+ blockId: string;
+ checkboxItems: CheckboxItem[];
+}
+
+export function Checkboxes({ blockId, checkboxItems, elementsLibrary }: Props) {
+ const [checkedById, setCheckedById] = useState>(() => loadCheckedState(blockId));
+
+ return (
+