{"id":13504318,"url":"https://github.com/elixir-lang/ex_doc","last_synced_at":"2026-01-31T09:10:47.580Z","repository":{"id":2652484,"uuid":"3642931","full_name":"elixir-lang/ex_doc","owner":"elixir-lang","description":"ExDoc produces HTML and EPUB documentation for Elixir projects","archived":false,"fork":false,"pushed_at":"2026-01-25T18:08:53.000Z","size":15632,"stargazers_count":1575,"open_issues_count":14,"forks_count":357,"subscribers_count":54,"default_branch":"main","last_synced_at":"2026-01-26T18:17:39.985Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://elixir-lang.org","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elixir-lang.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2012-03-06T21:35:38.000Z","updated_at":"2026-01-25T18:08:57.000Z","dependencies_parsed_at":"2024-02-19T17:16:35.743Z","dependency_job_id":"0e873f1b-f1fc-4b4d-9f82-58c8016ad231","html_url":"https://github.com/elixir-lang/ex_doc","commit_stats":{"total_commits":2468,"total_committers":217,"mean_commits":"11.373271889400922","dds":0.789708265802269,"last_synced_commit":"8bcbf19b0b599450f7209d6aa3e98ada68184103"},"previous_names":[],"tags_count":132,"template":false,"template_full_name":null,"purl":"pkg:github/elixir-lang/ex_doc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-lang%2Fex_doc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-lang%2Fex_doc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-lang%2Fex_doc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-lang%2Fex_doc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elixir-lang","download_url":"https://codeload.github.com/elixir-lang/ex_doc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elixir-lang%2Fex_doc/sbom","scorecard":{"id":254931,"data":{"date":"2025-08-11","repo":{"name":"github.com/elixir-lang/ex_doc","commit":"8ba731c9432b75447b0b89340eb8733881a79c95"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"name":"Code-Review","score":5,"reason":"Found 15/29 approved changesets -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":10,"reason":"11 commit(s) and 6 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Warn: topLevel 'contents' permission set to 'write': .github/workflows/release.yml:9","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":2,"reason":"dependency not pinned by hash detected -- score normalized to 2","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/artifacts.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/artifacts.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:35: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:49: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:67: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:91: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:93: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/elixir-lang/ex_doc/release.yml/main?enable=pin","Info:   0 out of   7 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v0.38.2 not signed: https://api.github.com/repos/elixir-lang/ex_doc/releases/221230543","Warn: release artifact v0.38.1 not signed: https://api.github.com/repos/elixir-lang/ex_doc/releases/217964556","Warn: release artifact v0.38.0 not signed: https://api.github.com/repos/elixir-lang/ex_doc/releases/217680679","Warn: release artifact v0.37.3 not signed: https://api.github.com/repos/elixir-lang/ex_doc/releases/204112233","Warn: release artifact v0.37.2 not signed: https://api.github.com/repos/elixir-lang/ex_doc/releases/201088393","Warn: release artifact v0.38.2 does not have provenance: https://api.github.com/repos/elixir-lang/ex_doc/releases/221230543","Warn: release artifact v0.38.1 does not have provenance: https://api.github.com/repos/elixir-lang/ex_doc/releases/217964556","Warn: release artifact v0.38.0 does not have provenance: https://api.github.com/repos/elixir-lang/ex_doc/releases/217680679","Warn: release artifact v0.37.3 does not have provenance: https://api.github.com/repos/elixir-lang/ex_doc/releases/204112233","Warn: release artifact v0.37.2 does not have provenance: https://api.github.com/repos/elixir-lang/ex_doc/releases/201088393"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":4,"reason":"6 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-67mh-4wv8-2f99","Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 18 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T09:25:25.467Z","repository_id":2652484,"created_at":"2025-08-17T09:25:25.468Z","updated_at":"2025-08-17T09:25:25.468Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28936100,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T08:53:31.997Z","status":"ssl_error","status_checked_at":"2026-01-31T08:51:38.521Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-08-01T00:00:29.526Z","updated_at":"2026-01-31T09:10:47.573Z","avatar_url":"https://github.com/elixir-lang.png","language":"Elixir","funding_links":[],"categories":["Installation","Documentation","Elixir","others"],"sub_categories":[],"readme":"# ExDoc\n\n[![Build Status](https://github.com/elixir-lang/ex_doc/workflows/CI/badge.svg)](https://github.com/elixir-lang/ex_doc/actions?query=workflow%3A%22CI%22)\n\nExDoc is a tool to generate documentation for Erlang and Elixir projects. To see an example, [you can access Elixir's official docs](https://hexdocs.pm/elixir/).\n\n## Features\n\nExDoc ships with many features:\n\n  * Automatically generates offline-accessible HTML, Markdown (including `llms.txt`), and EPUB documents from your API documentation.\n  * When hosted, ExDoc relies on browser's page transitions for better UX, caching, and enhanced accessibility.\n  * Responsive design, covering phones and tablets.\n  * Support for custom pages, guides, livebooks and cheatsheets.\n  * Support for custom grouping of modules, functions, and pages in the sidebar.\n  * Customizable logo and favicon.\n  * A direct link back to the source code for every documented entity.\n  * Full-text search.\n  * Keyboard shortcuts. (Press `?` to show help.)\n  * Quick-search with autocompletion support. (`s` keyboard shortcut.)\n  * Go-to shortcut with auto-complete to take the reader to any HexDocs package documentation. (`g` keyboard shortcut.)\n  * Support for night mode, activated according to the browser preference.\n  * Tooltips for links to modules and functions, both for the current project and other projects.\n  * Version dropdown and \"Go to latest\" notifications, automatically configured when hosted on HexDocs.\n\n## Usage\n\nYou can use ExDoc with Mix (recommended for Elixir projects), with Rebar (recommended for Erlang projects), or via the command line.\n\n\u003c!-- tabs-open --\u003e\n\n### Mix\n\nExDoc requires Elixir v1.15 or later. Then add ExDoc as a dependency:\n\n```elixir\ndef deps do\n  [\n    {:ex_doc, \"~\u003e 0.34\", only: :dev, runtime: false, warn_if_outdated: true},\n  ]\nend\n```\n\nThen run `mix deps.get`.\n\n\u003e #### Erlang development environment {: .warning}\n\u003e\n\u003e Some Operating System distributions split Erlang into multiple packages, and at least one ExDoc dependency (`earmark_parser`) requires the Erlang development environment. If you see a message like \"/usr/lib/erlang/lib/parsetools-2.3.1/include/yeccpre.hrl: no such file or directory\", it means you lack this environment. For instance, on the Debian operating system and its derivatives, you need to `apt install erlang-dev`.\n\nExDoc will automatically pull in information from your projects, such as the application and version. However, you may want to set `:name`, `:source_url` and `:homepage_url` in order to have nicer output from ExDoc:\n\n```elixir\ndef project do\n  [\n    app: :my_app,\n    version: \"0.1.0-dev\",\n    deps: deps(),\n\n    # Docs\n    name: \"MyApp\",\n    source_url: \"https://github.com/USER/PROJECT\",\n    homepage_url: \"http://YOUR_PROJECT_HOMEPAGE\",\n    docs: \u0026docs/0\n  ]\nend\n\ndefp docs do\n  [\n    main: \"readme\", # can be changed to a module name, if you prefer\n    logo: \"path/to/logo.png\",\n    extras: [\"README.md\"]\n  ]\nend\n```\n\nNow you are ready to generate your project documentation with `mix docs`. To see all options available, run `mix help docs`.\n\nTo learn about how to document your projects, see [Elixir's writing documentation page](https://hexdocs.pm/elixir/writing-documentation.html).\n\n### Rebar3\n\nFrom Erlang/OTP 24+, you can use ExDoc to render your Erlang documentation written with EDoc. See [`rebar3_ex_doc`](https://github.com/starbelly/rebar3_ex_doc/) for more information.\n\n### CLI\n\nYou can use ExDoc via the command line.\n\n1. Install ExDoc as an escript:\n\n   ```bash\n   $ mix escript.install hex ex_doc\n   ```\n\n2. Now you are ready to use it in your projects. Move into your project directory and make sure it's compiled:\n\n   ```bash\n   $ cd PATH_TO_YOUR_PROJECT\n   $ mix compile\n   ```\n\n3. Invoke the `ex_doc` executable from your project:\n\n   ```bash\n   $ ex_doc \"PROJECT_NAME\" \"PROJECT_VERSION\" _build/dev/lib/project/ebin -m \"PROJECT_MODULE\" -u \"https://github.com/GITHUB_USER/GITHUB_REPO\" -l path/to/logo.png\n   ```\n\n   Examples of appropriate values:\n\n   ```plain\n   PROJECT_NAME    =\u003e Ecto\n   PROJECT_VERSION =\u003e 0.1.0\n   PROJECT_MODULE  =\u003e Ecto (the main module provided by the library)\n   GITHUB_USER     =\u003e elixir-ecto\n   GITHUB_REPO     =\u003e ecto\n   ```\n\nIt is also possible to specify multiple `ebin` directories in the case of _umbrella_ projects:\n\n   ```bash\n   $ ex_doc \"PROJECT_NAME\" \"PROJECT_VERSION\" _build/dev/lib/app1/ebin _build/dev/lib/app2/ebin -m \"PROJECT_MODULE\" -u \"https://github.com/GITHUB_USER/GITHUB_REPO\" -l path/to/logo.png\n   ```\n\nIf multiple `ebin` directories are specified, modules are grouped by application by default. It is possible to override this behaviour by providing a custom `groups_per_modules` option.\n\nYou can specify a config file via the `--config` option, both Elixir and Erlang formats are supported. Invoke `ex_doc` without arguments to learn more.\n\n\u003c!-- tabs-close --\u003e\n\n## Syntax highlighting\n\nExDoc uses [the makeup project](https://github.com/elixir-makeup/makeup) for syntax highlighting. By default, highlighters for Erlang and Elixir are included. To syntax-highlight other languages, simply add the equivalent `makeup_LANGUAGE` package to your `mix.exs`/`rebar.config` file. For example, for HTML support you would add:\n\n\u003c!-- tabs-open --\u003e\n\n### Elixir (Mix)\n\n```elixir\n{:makeup_html, \"\u003e= 0.0.0\", only: :dev, runtime: false}\n```\n\n### Erlang (Rebar3)\n\n```erlang\n{makeup_html, \"0.1.1\"}\n```\n\n\u003c!-- tabs-close --\u003e\n\nYou can find all supported languages under [the Makeup organization on GitHub](https://github.com/elixir-makeup) and view them at [Makeup's website](https://elixir-makeup.github.io/makeup_demo/).\n\n## Additional pages\n\nYou can publish additional pages in your project documentation by configuring them as `:extras`. The following formats and extensions are supported:\n\n  * Markdown (`.md` extension) - useful for general long-term text. [Learn more](https://daringfireball.net/projects/markdown/syntax).\n\n  * Cheatsheets (`.cheatmd` extension) - useful for discovery and quick reference. [Learn more](https://hexdocs.pm/ex_doc/cheatsheet.html).\n\n  * Livebooks (`.livemd` extension) - useful for tutorials, interactive examples, and deep dives. [Learn more](https://livebook.dev/).\n\nFor example, you can set your `:extras` to:\n\n\u003c!-- tabs-open --\u003e\n\n### Elixir\n\n```elixir\nextras: [\"README.md\", \"LICENSE\", \"tutorial.livemd\", \"cheatsheet.cheatmd\"]\n```\n\nRun `mix help docs` for more information on configuration.\n\n### Erlang\n\n```elixir\n{extras, [\u003c\u003c\"README.md\"\u003e\u003e, \u003c\u003c\"cheatsheet.cheatmd\"\u003e\u003e]}.\n```\n\n\u003c!-- tabs-close --\u003e\n\n## Metadata\n\nExDoc supports metadata keys in your documentation.\n\n\u003c!-- tabs-open --\u003e\n\n### Elixir\n\nIn Elixir, you can add metadata to modules and functions.\n\nFor a module, use `@moduledoc`, which is equivalent to adding the annotation to everything inside the module (functions, macros, callbacks, types):\n\n```elixir\n@moduledoc since: \"1.10.0\"\n```\n\nFor a function, use `@doc`:\n\n```elixir\n@doc since: \"1.13.1\"\n```\n\n### Erlang\n\nIn Erlang's EDoc:\n\n```erlang\n%% @since 0.1.0\n```\n\n\u003c!-- tabs-close --\u003e\n\nThe following metadata is available for both modules and functions:\n\n  * `deprecated` (binary) - marks a module/function as deprecated, with the given string as the reason.\n  * `since` (binary) - declares a module/function available from a particular version.\n\nThe following metadata is available for modules:\n\n  * `tags` (list of atoms) - tags to be added as module annotations. (Not supported by EDoc.)\n\n## Auto-linking\n\nExDoc for Elixir and Erlang will automatically generate links across modules and functions if you enclose them in backticks.\n\n\u003c!-- tabs-open --\u003e\n\n### Elixir\n\nExDoc will automatically link modules, functions, types or callbacks defined in your project and its dependencies (including Erlang and Elixir). ExDoc will automatically link to the dependency's documentation at [hexdocs.pm](https://hexdocs.pm/). The link can be configured by setting `docs: [deps: [my_dep: \"https://path/to/docs/\"]]` in your `mix.exs`.\n\nExDoc supports linking to modules (`` `MyModule` `` and `` `m:MyModule` ``), functions (`` `MyModule.function/1` ``), types (`` `t:MyModule.type/2` ``) and callbacks (`` `c:MyModule.callback/3` ``). If you want to link a function, type or callback in the current module, you may skip the module name, for example: `` `function/1` ``. Similarly, you can automatically link to Erlang modules (`` `m::my_module` ``), functions (`` `:my_module.function/1` ``), types (`` `t::my_module.type/2` ``) and callbacks (`` `c::my_module.callback/3` ``) (since Erlang modules in Elixir start with `:`, note the double colon in some cases).\n\nYou can also use custom text, such as `` [custom text](`MyModule.function/1`) ``. Link to extra pages using the syntax `` [Up and running](Up and running.md) ``. The final link will be automatically converted to `up-and-running.html`.\n\nLink to extra pages in another application using the syntax `` [Writing Documentation](`e:elixir:writing-documentation.html`) ``, skipping the directory in which the page is. The final link will be automatically converted to `https://hexdocs.pm/elixir/writing-documentation.html`.\n\nIt is also possible to place anchors after the module name and extra pages. For example:\n\n  * `` `m:Keyword#module-duplicate-keys-and-ordering` `` will create a link to `https://hexdocs.pm/elixir/Keyword.html#module-duplicate-keys-and-ordering`\n\n  * `` `e:elixir:syntax-reference.md#expressions` `` will create a link to `https://hexdocs.pm/elixir/syntax-reference.html#expressions`\n\n### Erlang\n\nExDoc will automatically link modules, functions, types or callbacks defined in your project and its dependencies (including Erlang and Elixir). ExDoc will automatically link to it at the dependency's documentation at [hexdocs.pm](https://hexdocs.pm/). The link can be configured by setting `docs: [deps: [my_dep: \"https://path/to/docs/\"]]` in your `mix.exs`. The link can be configured by setting `{docs, [{deps,  [{my_dep, \"https://path/to/docs/\"}]}]}` in your `rebar3.config`.\n\nExDoc supports linking to modules (`` `m:my_module` ``), functions (`` `my_module:function/1` ``), types (`` `t:my_module:type/2` ``) and callbacks (`` `c:my_module:callback/3` ``). If you want to link a function, type or callback in the current module, you may skip the module name; e.g.: `` `function/1` ``.\n\nYou can also use custom text, such as `` [custom text](`my_module:function/1`) ``. This also allows you to refer to Erlang/OTP modules: `` [The array module](`array`) `` (note that when a module is given as the link target, it is not necessary nor possible to use the `m:` prefix).\n\nLink to extra pages using the syntax `` [Up and running](Up and running.md) ``. The final link will be automatically converted to `up-and-running.html`.\n\nLink to extra pages in another application using the syntax `` [Using unicode](`e:stdlib:unicode_usage.html`) ``, skipping the directory in which the page is. The final link will be automatically converted to `https://hexdocs.pm/elixir/writing-documentation.html`.\n\nIt is also possible to place anchors after the module name and extra pages. For example:\n\n  * `` `m:argparse#quick-start` `` will create a link to `https://erlang.org/doc/man/argparse#quick-start`\n\n  * `` `e:stdlib:unicode-usage.md#what-unicode-is` `` will create a link to `https://erlang.org/doc/apps/stdlib/unicode-usage.html#what-unicode-is`\n\n\u003c!-- tabs-close --\u003e\n\n## Admonition blocks\n\nYou may want to draw attention to certain statements by taking them out of the content's flow and labeling them with a priority. Such statements are called admonitions. (They are also known as asides or callouts.) An admonition block is rendered based on the assigned label or class. ExDoc supports `warning`, `error`, `info`, `tip` and `neutral` tags, on header levels `h3` and `h4`.\n\nThe syntax is as follows:\n\n```markdown\n\u003e #### Error {: .error}\n\u003e\n\u003e This syntax will render an error block\n```\n\nThe result for the previous syntax is:\n\n\u003e #### Error {: .error}\n\u003e\n\u003e This syntax will render an error block\n\nFor example, if you change the class name to `neutral`, you get the same admonition block in neutral style:\n\n\u003e #### Neutral {: .neutral}\n\u003e\n\u003e This syntax will render a neutral block\n\n## Tabsets\n\nWhere only one section of content of a series is likely to apply to the reader, you may wish to define a set of tabs.\n\nThis example contains code blocks, separating them into tabs based on language:\n\n\u003c!-- tabs-open --\u003e\n\n### Elixir\n\n```elixir\nIO.puts \"Hello, world!\"\n```\n\n### Erlang\n\n```erlang\nio:fwrite(\"Hello, world!\\n\").\n```\n\n\u003c!-- tabs-close --\u003e\n\nTabbed content must be defined between `\u003c!-- tabs-open --\u003e` and `\u003c!-- tabs-close --\u003e` HTML comments. Each `h3` heading results in a new tab panel, with its text setting the tab button label.\n\nHere is the above example's source:\n\n````markdown\n\u003c!-- tabs-open --\u003e\n\n### Elixir\n\n```elixir\nIO.puts \"Hello, world!\"\n```\n\n### Erlang\n\n```erlang\nio:fwrite(\"Hello, world!\\n\").\n```\n\n\u003c!-- tabs-close --\u003e\n````\n\n## Extensions\n\nExDoc renders Markdown content for you, but you can extend it to render complex objects on the page using JavaScript. To inject custom JavaScript into every page, add this to your configuration:\n\n```elixir\ndocs: [\n  # ...\n  before_closing_head_tag: \u0026before_closing_head_tag/1,\n  before_closing_body_tag: \u0026before_closing_body_tag/1\n]\n\n# ...\n\ndefp before_closing_head_tag(:html) do\n  \"\"\"\n  \u003c!-- HTML injected at the end of the \u003chead\u003e element --\u003e\n  \"\"\"\nend\n\ndefp before_closing_head_tag(:epub), do: \"\"\n\ndefp before_closing_body_tag(:html) do\n  \"\"\"\n  \u003c!-- HTML injected at the end of the \u003cbody\u003e element --\u003e\n  \"\"\"\nend\n\ndefp before_closing_body_tag(:epub), do: \"\"\n```\n\nBesides an anonymous function, you can also pass a `module-function-args` tuple. It will call the given module and function, with the format prefixed to the arguments:\n\n```elixir\ndocs: [\n  # ...\n  before_closing_head_tag: {MyModule, :before_closing_head_tag, []},\n  before_closing_body_tag: {MyModule, :before_closing_body_tag, []}\n]\n```\n\nOr you can pass a map where the key is the format:\n\n```elixir\ndocs: [\n  # ...\n  before_closing_head_tag: %{html: \"...\", epub: \"...\"},\n  before_closing_body_tag: %{html: \"...\", epub: \"...\"}\n]\n```\n\nOn the JavaScript side, ExDoc emits the `\"exdoc:loaded\"` event. This event may be called multiple times, as you navigate across pages, so initialization that should happen only once must be conditional. We recommend external scripts to use `defer`, not `async`, as shown in the examples below.\n\n### Rendering Math\n\nIf you write TeX-style math in your Markdown, such as `$\\sum_{i}^{N} x_i$`, it ends up as raw text on the generated pages. To render expressions, we recommend using [KaTeX](https://katex.org/), a JavaScript library that turns expressions into graphics. To load and trigger KaTeX on every documentation page, we can insert the following HTML:\n\n```html\n\u003clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css\" integrity=\"sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0\" crossorigin=\"anonymous\"\u003e\n\u003cscript defer src=\"https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.js\" integrity=\"sha384-PwRUT/YqbnEjkZO0zZxNqcxACrXe+j766U2amXcgMg5457rve2Y7I6ZJSm2A0mS4\" crossorigin=\"anonymous\"\u003e\u003c/script\u003e\n\n\u003clink href=\"https://cdn.jsdelivr.net/npm/katex-copytex@1.0.2/dist/katex-copytex.min.css\" rel=\"stylesheet\" type=\"text/css\"\u003e\n\u003cscript defer src=\"https://cdn.jsdelivr.net/npm/katex-copytex@1.0.2/dist/katex-copytex.min.js\" crossorigin=\"anonymous\"\u003e\u003c/script\u003e\n\n\u003cscript defer src=\"https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/contrib/auto-render.min.js\" integrity=\"sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05\" crossorigin=\"anonymous\"\u003e\u003c/script\u003e\n\n\u003cscript\u003e\n  window.addEventListener(\"exdoc:loaded\", () =\u003e {\n    renderMathInElement(document.body, {\n      delimiters: [\n        {left: '$$', right: '$$', display: true},\n        {left: '$', right: '$', display: false},\n      ]\n    })\n  })\n\u003c/script\u003e\n```\n\nFor more details and configuration options, see the [KaTeX Auto-render Extension](https://katex.org/docs/autorender.html).\n\n### Rendering Vega-Lite plots\n\nSnippets are also objects you may want to render in a special manner. For example, assuming your Markdown includes Vega-Lite specification in `vega-lite` code snippets:\n\n```html\n\u003cscript defer src=\"https://cdn.jsdelivr.net/npm/vega@5.20.2\"\u003e\u003c/script\u003e\n\u003cscript defer src=\"https://cdn.jsdelivr.net/npm/vega-lite@5.1.1\"\u003e\u003c/script\u003e\n\u003cscript defer src=\"https://cdn.jsdelivr.net/npm/vega-embed@6.18.2\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  window.addEventListener(\"exdoc:loaded\", () =\u003e {\n    for (const codeEl of document.querySelectorAll(\"pre code.vega-lite\")) {\n      try {\n        const preEl = codeEl.parentElement;\n        const spec = JSON.parse(codeEl.textContent);\n        const plotEl = document.createElement(\"div\");\n        preEl.insertAdjacentElement(\"afterend\", plotEl);\n        vegaEmbed(plotEl, spec);\n        preEl.remove();\n      } catch (error) {\n        console.log(\"Failed to render Vega-Lite plot: \" + error)\n      }\n    }\n  });\n\u003c/script\u003e\n```\n\nFor more details and configuration options, see [vega/vega-embed](https://github.com/vega/vega-embed).\n\n### Rendering Mermaid graphs\n\nSimilarly to the example above, if your Markdown includes Mermaid graph specification in `mermaid` code snippets:\n\n```html\n\u003cscript defer src=\"https://cdn.jsdelivr.net/npm/mermaid@10.2.3/dist/mermaid.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  let initialized = false;\n\n  window.addEventListener(\"exdoc:loaded\", () =\u003e {\n    if (!initialized) {\n      mermaid.initialize({\n        startOnLoad: false,\n        theme: document.body.className.includes(\"dark\") ? \"dark\" : \"default\"\n      });\n      initialized = true;\n    }\n\n    let id = 0;\n    for (const codeEl of document.querySelectorAll(\"pre code.mermaid\")) {\n      const preEl = codeEl.parentElement;\n      const graphDefinition = codeEl.textContent;\n      const graphEl = document.createElement(\"div\");\n      const graphId = \"mermaid-graph-\" + id++;\n      mermaid.render(graphId, graphDefinition).then(({svg, bindFunctions}) =\u003e {\n        graphEl.innerHTML = svg;\n        bindFunctions?.(graphEl);\n        preEl.insertAdjacentElement(\"afterend\", graphEl);\n        preEl.remove();\n      });\n    }\n  });\n\u003c/script\u003e\n```\n\nFor more details and configuration options, see the [Mermaid usage docs](https://mermaid-js.github.io/mermaid/#/usage).\n\n## Contributing\n\nThe easiest way to test changes to ExDoc is to locally rebuild the app and its own documentation:\n\n  1. Run `mix setup` to install all dependencies\n  2. Run `mix build` to generate the docs and open up the generated `doc/index.html`\n  3. (optional) Run `erl -S httpd serve doc/` to serve the docs locally\n  4. (optional) Run `npm run --prefix assets build:watch` if working on assets for automatic recompilation\n  5. Run `mix lint` to check linting and formatting (and `mix fix` to automatically fix it)\n  6. (important) Do not add the files in the `formatters/` directory to your commits, those will be handled by the maintainers\n\nSee the README in the `assets/` directory for more information on working on the assets.\n\n## License\n\nExDoc source code is released under the Apache 2 License. The generated contents, however, are under different licenses based on projects used to help render HTML, including CSS, JS, and other assets.\n\nAny documentation generated by ExDoc, or any documentation generated by any \"Derivative Works\" (as specified in the Apache 2 License), must include a direct, readable, and visible link to the [ExDoc repository](https://github.com/elixir-lang/ex_doc) on each rendered material. For HTML pages, every single page is a rendered material. For PDF, EPUB and other ebook formats, the whole body of documentation is a rendered material.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-lang%2Fex_doc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felixir-lang%2Fex_doc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felixir-lang%2Fex_doc/lists"}