{"id":13407927,"url":"https://github.com/portabletext/portabletext","last_synced_at":"2025-05-15T23:04:25.355Z","repository":{"id":40523945,"uuid":"159509000","full_name":"portabletext/portabletext","owner":"portabletext","description":"Portable Text is a JSON based rich text specification for modern content editing platforms.","archived":false,"fork":false,"pushed_at":"2024-07-25T12:58:17.000Z","size":45,"stargazers_count":1278,"open_issues_count":14,"forks_count":22,"subscribers_count":20,"default_branch":"main","last_synced_at":"2024-10-29T15:27:08.483Z","etag":null,"topics":["json","markup","portable-text","text"],"latest_commit_sha":null,"homepage":"https://www.portabletext.org","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/portabletext.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-28T13:47:13.000Z","updated_at":"2024-10-28T07:58:29.000Z","dependencies_parsed_at":"2024-01-06T02:03:55.521Z","dependency_job_id":"c6170526-3070-4229-be18-aab8ed19098f","html_url":"https://github.com/portabletext/portabletext","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/portabletext%2Fportabletext","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/portabletext%2Fportabletext/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/portabletext%2Fportabletext/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/portabletext%2Fportabletext/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/portabletext","download_url":"https://codeload.github.com/portabletext/portabletext/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254436944,"owners_count":22070946,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","markup","portable-text","text"],"created_at":"2024-07-30T20:00:49.528Z","updated_at":"2025-05-15T23:04:25.338Z","avatar_url":"https://github.com/portabletext.png","language":null,"funding_links":[],"categories":["Related projects","Others","json"],"sub_categories":["Studio Inspiration"],"readme":"\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/portabletext/portabletext/master/logo-white.svg?sanitize=true\"\u003e\n  \u003cimg alt=\"Portable Text Logo\" src=\"https://raw.githubusercontent.com/portabletext/portabletext/master/logo.svg?sanitize=true\"\u003e\n\u003c/picture\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n\u003ch1\u003e Specification for Portable Text\u003c/h1\u003e\n\n\u003cp\u003ev0.0.1 - WORKING DRAFT\u003c/p\u003e\n\n\u003c/div\u003e\n\n\u003e Portable Text is a JSON based rich text specification for modern content editing platforms.\n\nPortable Text is an agnostic abstraction of rich text that can be serialized into pretty much any markup language, be it HTML, Markdown, SSML, XML, etc. It's designed to be efficient for real-time collaborative interfaces, and makes it possible to annotate rich text with additional data structures recursively.\n\nPortable Text is built on the idea of rich text as an array of blocks, themselves arrays of children spans. Each block can have a style and a set of mark definitions, which describe data structures distributed on the children spans. Portable Text also allows for inserting arbitrary data objects in the array, only requiring `_type`-key. Portable Text also allows for custom content objects in the root array, enabling editing- and rendering environments to mix rich text with custom content types.\n\nExample of a text block with some text annotated with some data:\n\n```json\n{\n  \"style\": \"normal\",\n  \"_type\": \"block\",\n  \"children\": [\n    {\n      \"_type\": \"span\",\n      \"marks\": [\"a-key\", \"emphasis\"],\n      \"text\": \"some text\"\n    }\n  ],\n  \"markDefs\": [\n    {\n      \"_key\": \"a-key\",\n      \"_type\": \"markType\",\n      \"extraData\": \"some data\"\n    }\n  ]\n}\n```\n\n## Anatomy\n\nPortable Text is a recursive composition of arrays and objects. In its simplest form it's an array of objects of a `type` with an array of `children`.\n\n### Block\n\nA block is what's typically recognized as a section of a text, e.g. a paragraph or a heading.\n\n#### children (array)\n\nChildren is an array of spans or custom inline types that is contained within a block.\n\n#### \\_type (string)\n\nAll blocks must be of a type. The type makes it possible for a serializer to parse the contents of the block.\n\n#### style (string)\n\nStyle typically describes a visual property for the whole block.\n\n```json\n{\n  \"style\": \"h1\",\n  \"_type\": \"block\",\n  \"children\": [\n    {\n      \"_type\": \"span\",\n      \"text\": \"This is a heading\"\n    }\n  ]\n}\n```\n\n#### markDefs (array)\n\nMark definitions is an array of objects with a key, type and some data. Mark definitions are tied to `spans` by adding the referring `_key` in the `marks` array.\n\n```json\n{\n  \"markDefs\": [\n    {\n      \"_key\": \"some-random-key\",\n      \"_type\": \"link\",\n      \"href\": \"https://portabletext.org\"\n    },\n    {\n      \"_key\": \"some-other-random-key\",\n      \"_type\": \"comment\",\n      \"text\": \"Change to https://\",\n      \"author\": \"some-author-id\"\n    }\n  ]\n}\n```\n\n#### listItem\n\nA block can be given the property `listItem` with a value that describes which kind of list it is. Typically `bullet`, `number`, `square` and so on. The list position is derived from the position the block has in the array and surrounding list items on the same level.\n\n#### level\n\nLevel is used to express visual nesting and hierarchical structures between blocks in the array.\n\n### span\n\nA span is the standard way to express inline text within a block\n\n#### \\_type (string)\n\nAll children must be typed. The type makes it possible for a serializer to parse the contents of the child.\n\n#### marks (array)\n\nMarks are how we mark up inline text with additional data/features. Marks comes in two forms: Decorators and Annotations. Decorators are marks as simple string values, while Annotations are keys to a data structure. `marks` is therefore either an array of string values, or keys, corresponding to `markDefs`, with the same `_key`. See the examples below, or check out this [live CodeSandbox example with an inline image and a link](https://codesandbox.io/s/awesome-sammet-71gy8?file=/src/App.js):\n\nDecorator example:\n\n```json\n[\n  {\n    \"_type\": \"span\",\n    \"marks\": [],\n    \"text\": \"This is\"\n  },\n  {\n    \"_type\": \"span\",\n    \"marks\": [\"emphasis\"],\n    \"text\": \"important\"\n  }\n]\n```\n\nAnnotation example:\n\n```json\n[\n  {\n    \"_type\": \"block\",\n    \"children\": [\n      {\n        \"_type\": \"span\",\n        \"text\": \"Portable Text\",\n        \"marks\": [\"\u003cmarkDefId\u003e\"] // this corresponds to a `\"_key\"` in `markDefs`\n      }\n    ],\n    \"markDefs\": [\n      {\n        \"_type\": \"link\",\n        \"_key\": \"\u003cmarkDefId\u003e\", // this corresponds to a value in `children.marks`\n        \"href\": \"https://www.portabletext.org\"\n      }\n    ]\n  }\n]\n```\n\n#### Text (string)\n\nThe text contents of the span.\n\n### Custom blocks\n\nCustom blocks are typically images (for inline images, see the marks section), code blocks, tables, video embeds, or any data structure. Custom blocks should be given a `_type`.\n\nExamples of custom blocks:\n\n```json\n{\n  \"_type\": \"image\",\n  \"asset\": {\n    \"_ref\": \"some-asset-reference\"\n  }\n}\n```\n\n```json\n{\n  \"_type\": \"code\",\n  \"language\": \"javascript\",\n  \"code\": \"console.log(\\\"hello world\\\");\"\n}\n```\n\n## Serialization\n\n### Tools\n\n#### JavaScript\n\n- [@portabletext/react](https://github.com/portabletext/react-portabletext)\n- [@portabletext/svelte](https://github.com/portabletext/svelte-portabletext/)\n- [@portabletext/vue](https://github.com/portabletext/vue-portabletext/)\n- [@portabletext/to-html](https://github.com/portabletext/to-html/)\n- [@portabletext/block-tools](https://www.npmjs.com/package/%40portabletext/block-tools)\n- [@limitless-angular/sanity/portable-text](https://github.com/limitless-angular/limitless-angular/blob/main/libs/sanity/portabletext/README.md)\n- [@sanity/block-content-to-hyperscript](https://www.npmjs.com/package/%40sanity/block-content-to-hyperscript)\n- [@sanity/block-content-to-markdown](https://www.npmjs.com/package/%40sanity/block-content-to-markdown)\n- [theisel/astro-portabletext](https://github.com/theisel/astro-portabletext)\n\n#### PHP\n\n- The `Sanity\\BlockContent` class in [the sanity-php client](https://github.com/sanity-io/sanity-php)\n\n#### Python\n\n- [portabletext-html](https://github.com/otovo/python-portabletext-html)\n\n#### C#\n\n- The `SanityHtmlBuilder` class in [the Sanity LINQ client](https://github.com/oslofjord/sanity-linq)\n- [Portable Text .NET](https://github.com/nhi/portable-text-dotnet), a C# HTML converter to Portable Text, also supporting custom types. (A graceful port of [`blockTools.htmlToBlocks()`](https://www.npmjs.com/package/@portabletext/block-tools#htmltoblockshtml-blockcontenttype-options-html-deserializer) to C#)\n\n#### Dart/Flutter\n\n- [Flutter Widget for Portable Text](https://pub.dev/packages/flutter_sanity_portable_text): Supports the entire spec of Portable Text with an easy to use Widget. It also includes support for **custom** blocks, marks, gestures, styles in an extensible manner. Use this package in conjunction with the [Sanity Client](https://pub.dev/packages/sanity_client) package for deserializing Portable Text in documents from Sanity.\n- [flutter_portabletext](https://github.com/JobiJoba/flutter_portabletext)\n\n---\n\nPortable Text is presented by [Sanity.io](https://github.com/sanity-io)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fportabletext%2Fportabletext","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fportabletext%2Fportabletext","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fportabletext%2Fportabletext/lists"}