Roam Research Docs · Developer documentation
{{}}
{{roam/render: ((<block-reference>))}}.
(defn hello-world []
[:div
{:style {:color "blue"}}
"hello world"])
{{roam/render: ((uD2gB7Qvh))}}
(defn hello-world []
[:div
{:style {:color "blue"}}
"hello world"])}}
(ns dev-docs.hello-world)
(defn main []
[:h1 "Hello world from CLJS"])
{{roam/render: ((ltUELYamK))}}
(ns dev-docs.hello-world)
(defn main []
[:h1 "Hello world from CLJS"])}}
(defn main-args-1 [{:keys [block-uid]} & args]
[:div
[:h1 (str block-uid ": args: ")]
[:ul
(for [arg args]
[:li (pr-str arg)])]])
(defn main-args-1 [{:keys [block-uid]} & args]
[:div
[:h1 (str block-uid ": args: ")]
[:ul
(for [arg args]
[:li (pr-str arg)])]]) "arg-1" 2 test args test block args}}
(ns dev-docs.parse-example
(:require [roam.util :refer [parse]]))
(defn main []
[parse "**apple** __banana__ [[test-parse]]"])
{{[[roam/render]]: ((uUxqZ4Bwb))}}
(ns dev-docs.parse-example
(:require [roam.util :refer [parse]]))
(defn main []
[parse "**apple** __banana__ [[test-parse]]"])}}
(ns katex-example
(:require
[reagent.core :as r]
[roam.katex :as katex]))
(defn inline-example []
(let [*val (r/atom "")]
(fn []
[:div
[:input
{:value @*val
:on-change #(reset! *val (.. % -target -value))}]
[:div
"Inline katex: "
[katex/inline
@*val]]])))
{{roam/render: ((ydU0Dpoq_))}}
(defn inline-example []
(let [*val (r/atom "")]
(fn []
[:div
[:input
{:value @*val
:on-change #(reset! *val (.. % -target -value))}]
[:div
"Inline katex: "
[katex/inline
@*val]]])))}}
(defn block-example []
(let [*val (r/atom "")]
(fn []
[:div
[:input
{:value @*val
:on-change #(reset! *val (.. % -target -value))}]
[:div
"Block katex: "
[katex/block
@*val]]])))
{{roam/render: ((cF6Xzv0bd))}}
(defn block-example []
(let [*val (r/atom "")]
(fn []
[:div
[:input
{:value @*val
:on-change #(reset! *val (.. % -target -value))}]
[:div
"Block katex: "
[katex/block
@*val]]])))}}
roam.datascript.reactive is identical to roam.datascript except that every function returns a reagent reactions, which updates when the result of the query or pull changes.
r/with-let below. Any time you use r/atom or any function from roam.datascript.reactive you should define it inside of a form 2 or form 3 component
(ns dev-docs.get-page-blocks-with-tag
(:require
[roam.datascript.reactive :as dr]
[roam.util :as u]
[roam.ui.main-window :as main-window]
[reagent.core :as r]))
(defn track-blocks-with-tag-on-page [tag-uid page-uid]
(dr/q
'[:find (pull ?page-block [:block/uid :block/string])
:in $ ?tag-uid ?page-uid
:where
[?tag-e :block/uid ?tag-uid]
[?page-e :block/uid ?page-uid]
[?page-block :block/page ?page-e]
[?page-block :block/refs ?tag-e]]
tag-uid
page-uid))
(defn main [{:keys [block-uid]} [_ tag-uid] [_ page-uid]]
(r/with-let [*blocks (track-blocks-with-tag-on-page tag-uid page-uid)]
(into [:ul]
(keep (fn [[{:keys [block/string block/uid]}]]
(when (not= uid block-uid)
[:li
{:style {:cursor "pointer"}
:on-click (fn []
(main-window/open-block
{:block {:uid uid}}))}
[u/parse string]])))
@*blocks)))
{{roam/render: ((o5wWBZxdg))}}
ns-publics can be useful when trying to figure out what a namespace exports. In this example we pass in a ns-name and display all of the functions / vars in a namespace
(ns ns-vars-lister
(:require [reagent.core]))
(defn main [{:keys [block-uid]} ns-name]
(let [ns-symbol (symbol ns-name)]
[:div [:div
[:h3 "public vars of ns: " (pr-str ns-symbol)]
[:div (map
(fn [n] [:div (pr-str n)])
(->> (ns-publics ns-symbol)
(seq)
(sort)))]]]))
{{roam/render: ((r47yvGHoi)) "reagent.core"}}
(ns ns-vars-lister
(:require [reagent.core]))
(defn main [{:keys [block-uid]} ns-name]
(let [ns-symbol (symbol ns-name)]
[:div [:div
[:h3 "public vars of ns: " (pr-str ns-symbol)]
[:div (map
(fn [n] [:div (pr-str n)])
(->> (ns-publics ns-symbol)
(seq)
(sort)))]]])) "reagent.core"}}
instaparse.core readme example
(ns developer-documentation.test-instaparse.1
(:require
[reagent.core :as r]
[roam.block :as block]
[blueprintjs.core :as bp-core]
[cljs.pprint :refer [pprint]]
[instaparse.core :as insta]))
(def as-and-bs
(insta/parser
"S = AB*
AB = A B
A = 'a'+
B = 'b'+"))
(defn main [{:keys [block-uid]}]
[:button
{:on-click
#(pprint (as-and-bs "aaaaabbbaaaabb"))} "Click me!"])
{{[[roam/render]]: ((6DXyUOHhH))}}
(ns developer-documentation.test-instaparse.1
(:require
[reagent.core :as r]
[roam.block :as block]
[blueprintjs.core :as bp-core]
[cljs.pprint :refer [pprint]]
[instaparse.core :as insta]))
(def as-and-bs
(insta/parser
"S = AB*
AB = A B
A = 'a'+
B = 'b'+"))
(defn main [{:keys [block-uid]}]
[:button
{:on-click
#(pprint (as-and-bs "aaaaabbbaaaabb"))} "Click me!"])}} (check console after clicking)
blueprintjs.core
(ns dev-docs.test-blueprint.1
(:require
[reagent.core :as r]
[roam.block :as block]
[blueprintjs.core :as bp-core]))
(defonce bp3-button (r/adapt-react-class bp-core/Button))
(defn main [{:keys [block-uid]}]
[bp3-button
{:large true
:disabled true
:icon "history"
:on-click
#(block/update
{:block {:uid block-uid
:string "Hello world!"}})}
"Click me!"])
{{[[roam/render]]: ((O1iyYWZsW))}}
(ns dev-docs.test-blueprint.1
(:require
[reagent.core :as r]
[roam.block :as block]
[blueprintjs.core :as bp-core]))
(defonce bp3-button (r/adapt-react-class bp-core/Button))
(defn main [{:keys [block-uid]}]
[bp3-button
{:large true
:disabled true
:icon "history"
:on-click
#(block/update
{:block {:uid block-uid
:string "Hello world!"}})}
"Click me!"])}}
{{[[roam/render]]: ((Hcuh0h3ys))}}
(ns render-examples.confetti
(:require
[reagent.core :as r]
;; require any package from npm
["canvas-confetti" :as confetti]
;; require a specific version of a package
["[email protected]" :refer [AwesomeButton]]
;; require css for an npm package
["[email protected]/dist/styles.css"]
;; alternatively you could use CDN of your choice by providing a full URL
;; internally we use esm.sh to load npm packages
#_["https://cdn.skypack.dev/[email protected]/dist/styles.css"]))
(def awesome-button (r/adapt-react-class AwesomeButton))
(defn main []
[:div
[awesome-button
{:type "primary"
;; be careful, some packages export default, which is not auto processed by cljs as it is in js
;; when in doubt, print out what your var is
:onPress #(confetti/default)}
"Fun!"]])}}
(ns render-examples.confetti
(:require
[reagent.core :as r]
;; require any package from npm
["canvas-confetti" :as confetti]
;; require a specific version of a package
["[email protected]" :refer [AwesomeButton]]
;; require css for an npm package
["[email protected]/dist/styles.css"]
;; alternatively you could use CDN of your choice by providing a full URL
;; internally we use esm.sh to load npm packages
#_["https://cdn.skypack.dev/[email protected]/dist/styles.css"]))
(def awesome-button (r/adapt-react-class AwesomeButton))
(defn main []
[:div
[awesome-button
{:type "primary"
;; be careful, some packages export default, which is not auto processed by cljs as it is in js
;; when in doubt, print out what your var is
:onPress #(confetti/default)}
"Fun!"]])
function main2 () {
return <h1>Hello world from JSX</h1>
}
{{roam/render: ((hlu_MicTh))}}
function main2 () {
return <h1>Hello world from JSX</h1>
}}}
function mainArgs3({args}) {
let block, actualArgs;
[block, ...actualArgs] = args;
const listArgs = actualArgs.map(
(arg) => <li>{arg.toString()}</li>
);
return (
<div>
<h1>
{block["block-uid"]}: args:
</h1>
<ul>{listArgs}</ul>
</div>
);
}
function mainArgs3({args}) {
let block, actualArgs;
[block, ...actualArgs] = args;
const listArgs = actualArgs.map(
(arg) => <li>{arg.toString()}</li>
);
return (
<div>
<h1>
{block["block-uid"]}: args:
</h1>
<ul>{listArgs}</ul>
</div>
);
} "arg-1" 2 test args test block args}}
function main1() {
return React.createElement('h1', {}, 'Hello world from JS');
}
{{roam/render: ((qfcNnWG7J))}}
function main1() {
return React.createElement('h1', {}, 'Hello world from JS');
}}}
function mainArgs2({args}) {
let block, actualArgs;
[block, ...actualArgs] = args;
console.log(block, actualArgs)
return React.createElement('div', {}, "Hello");
}
{{roam/render: ((zJX0nWRLX)) "arg-1" 2 [[test args]] ((7lN0hyokF))}}
function mainArgs2({args}) {
let block, actualArgs;
[block, ...actualArgs] = args;
console.log(block, actualArgs)
return React.createElement('div', {}, "Hello");
} "arg-1" 2 test args test block args}}
block-uid of the block the component is rendered inside of (not the uid of the code block!)
{:block-uid "KjccJWpBM"} (clojure) or {"block-uid": "KjccJWpBM"} (js)
{{roam/render: ((KjccJWpBM)) "arg-1" 2}}
KjccJWpBM and pass the arguments "arg-1" and 2
cljs.reader)
{:block-uid "KjccJWpBM"} (clojure) or {"block-uid": "KjccJWpBM"} (js)
"arg-1"
2
{{roam/render: ((KjccJWpBM)) [[test args]] ((7lN0hyokF))}}
{:block-uid "KjccJWpBM"} (clojure) or {"block-uid": "KjccJWpBM"} (js)
[:block/uid "MFSo6yX_Q"] (clojure) or ['uid', 'MFSo6yX_Q'] (js)
[:block/uid "7lN0hyokF"] or ['uid', '7lN0hyokF'] (js)
(defn main-args-1 [{:keys [block-uid]} & args]
[:div
[:h1 (str block-uid ": args: ")]
[:ul
(for [arg args]
[:li (pr-str arg)])]])
(defn main-args-1 [{:keys [block-uid]} & args]
[:div
[:h1 (str block-uid ": args: ")]
[:ul
(for [arg args]
[:li (pr-str arg)])]]) "arg-1" 2 test args test block args}}
function mainArgs2({args}) {
let block, actualArgs;
[block, ...actualArgs] = args;
console.log(block, actualArgs)
return React.createElement('div', {}, "Hello");
}
{{roam/render: ((zJX0nWRLX)) "arg-1" 2 [[test args]] ((7lN0hyokF))}}
function mainArgs2({args}) {
let block, actualArgs;
[block, ...actualArgs] = args;
console.log(block, actualArgs)
return React.createElement('div', {}, "Hello");
} "arg-1" 2 test args test block args}}
function mainArgs3({args}) {
let block, actualArgs;
[block, ...actualArgs] = args;
const listArgs = actualArgs.map(
(arg) => <li>{arg.toString()}</li>
);
return (
<div>
<h1>
{block["block-uid"]}: args:
</h1>
<ul>{listArgs}</ul>
</div>
);
}
function mainArgs3({args}) {
let block, actualArgs;
[block, ...actualArgs] = args;
const listArgs = actualArgs.map(
(arg) => <li>{arg.toString()}</li>
);
return (
<div>
<h1>
{block["block-uid"]}: args:
</h1>
<ul>{listArgs}</ul>
</div>
);
} "arg-1" 2 test args test block args}}
eval
markdown version · view in Roam Research · exported 2026-07-03