| name | folio-tiptap-node |
| description | Creates and edits custom Tiptap block-editor nodes in Folio: the node model (Folio::Tiptap::Node subclass with tiptap_node structure), the view component for rendering, tiptap_config (icons, groups, paste), and i18n. Use when adding a new Tiptap node, editing node structure or rendering, wiring node groups/icons, or when the user mentions `rails g folio:tiptap:node`. |
Tiptap Node development (Folio)
Path resolution: This skill references Folio repo files (e.g. docs/tiptap.md).
In the Folio gem itself, use paths as-is. In a host app, resolve from the gem
root: bundle show folio.
Prerequisites
- Read
docs/tiptap.md — full tiptap architecture, attribute types, data structure, rendering flow, icons, groups, paste config, and CSS. Do not rely on memory alone.
- Follow
.skills/folio-view-component/SKILL.md for component conventions (BEM, Slim, testing rules, composition) — this skill only covers the tiptap-node-specific layer.
Generator
Always use the generator for new nodes — do not create files by hand:
rails generate folio:tiptap:node contents/text
This creates (under the host app's namespace, e.g. MyApp):
| File | Purpose |
|---|
app/models/my_app/tiptap/node/contents/text.rb | Node model (< Folio::Tiptap::Node) |
app/components/my_app/tiptap/node/contents/text_component.rb | View component |
app/components/my_app/tiptap/node/contents/text_component.slim | Slim template |
test/components/my_app/tiptap/node/contents/text_component_test.rb | Component test |
app/components/my_app/tiptap/node/base_component.rb | Base component (created once, shared initialize(node:, tiptap_content_information:)) |
config/locales/tiptap/nodes.*.yml | i18n entries |
Node model
Define structure and config with tiptap_node. For attribute types, tiptap_config options (icons, groups, toolbar slots, paste), and placeholder/hint — see docs/tiptap.md (Custom Node Implementation).
- Use
group only with keys defined in the app's node_groups.
- Add
toolbar_slot to a node rarely, only for the most common quick-access nodes such as "single image". Do not add it just because the node has group.
class MyApp::Tiptap::Node::Contents::Text < Folio::Tiptap::Node
tiptap_node structure: {
content: :rich_text,
}, tiptap_config: {
icon: "content_text",
group: "content",
}
end
View component
The generated component inherits from the base component. The template receives @node and @tiptap_content_information (keys documented in docs/tiptap.md).
BEM class follows the same rules as regular ViewComponents (see folio-view-component skill). Use @tiptap_content_information[:editor_preview] to conditionally simplify rendering inside the editor iframe.
Testing
Tests subclass Folio::Tiptap::NodeComponentTest (extends Folio::ComponentTest).
Follow .skills/folio-testing/SKILL.md for
rendered-output assertions and one-render-per-test guidance.
The tiptap_content_information helper and create_test_tiptap_node are provided by the test base class.
class MyApp::Tiptap::Node::Contents::TextComponentTest < Folio::Tiptap::NodeComponentTest
def test_render
node = create_test_tiptap_node(MyApp::Tiptap::Node::Contents::Text)
render_inline(MyApp::Tiptap::Node::Contents::TextComponent.new(node:, tiptap_content_information:))
assert_selector(".m-tiptap-node-contents-text")
end
end
Wiring into the app
Register new nodes in the app's default_tiptap_config (see docs/tiptap.md for group and icon configuration):
def self.default_tiptap_config
::Folio::Tiptap::Config.new(
node_names: %w[
MyApp::Tiptap::Node::Contents::Text
],
node_groups: [
{ key: "content", title: { cs: "Obsah", en: "Content" },
icon: "content" },
],
)
end
Only add toolbar_slot to a node_groups entry when that group should render
as a toolbar dropdown. Prefer leaving groups out of the toolbar unless they hold
very common insertion actions; groups without toolbar_slot remain available
for slash command organization only.
i18n
The generator creates entries in config/locales/tiptap/nodes.*.yml. Add attribute translations under the node key; for default: / hint: procs, use nested keys like title/default.
Quality gates
After edits: rubocop --autocorrect-all on Ruby, slim-lint on Slim, npx standard --fix on JS (see AGENTS.md).
Reference
- Generator:
lib/generators/folio/tiptap/node/node_generator.rb
- Node base class:
app/models/folio/tiptap/node.rb
- Test base:
Folio::Tiptap::NodeComponentTest in test/test_helper_base.rb
- Full tiptap docs:
docs/tiptap.md
- ViewComponent conventions:
.skills/folio-view-component/SKILL.md