Skip to main content
Skip table of contents

How to create accessible GitHub Markdown files

Last updated: August 18, 2025

This guide explains how to create Markdown files on GitHub that are accessible to assistive technology users.

About GitHub Markdown files 

Markdown is a markup language used to create formatted text. Markdown files are easy to read and write by both humans and computers.

In VA GitHub repositories, we use Markdown to create documentation, such as research plans, conversation guides, research reports, and readme files. The Accessibility Digital Experience team’s readme page is one example.

To learn more about creating GitHub Markdown files, read GitHub’s documentation, starting with Quickstart for writing on GitHub.

Accessible GitHub Markdown best practices

Use headings, not bolded text

Many assistive technology users navigate web pages by heading. They may access a list of headings on the page and pick the one they’re interested in, or use a shortcut to jump between headings. Bolded text may look like a heading, but it isn’t conveyed as a heading to assistive technology.

Use the pound sign, #, to create headings and subheadings in Markdown. The number of pound signs represents the heading level - # for level 1, ## for level 2, etc.

  • Do this: ## My heading

  • Not this: **Not a heading**

Create a logical heading structure.

  • Do this:
    ### My favorite things
    #### Books

  • Not this:
    ### My favorite things
    ##### Books

    • Why not? Because there’s a level 3 but not a level 4 before the level 5

Create meaningful alt text for every image

Every image in a Markdown file needs a meaningful text description, or “alt text,” so that users who can’t see the image have equal access to its information. 

When you link to an image, use either of these formats: 

  • [your alt text](image URL)

  • <image alt=”your alt text” src=”image URL”> 

In GitHub, If you upload an image directly to the file or comment, it creates code in this format: <image width=”” height=”” alt=”Image” src=”image URL”>. Replace “Image” with meaningful alt text.

  • Do this: [VA Profile user interface. The View payment history link has focus.](image URL)

  • Not this: [](image URL)

    • Why not? Because the alt text is missing

  • Do this: <image alt=”Research participant accesses VA.gov on their iPhone” src=”image URL”>

  • Not this: <image alt=”Image” src=”image URL”>

    • Why not? Because alt text needs to be more specific than the word “Image”

Many screen reader users navigate web pages by either tabbing through interactive elements or selecting from a list of the links on the page. Because of this, every link must be able to stand on its own without any of the surrounding content. And the link text must be unique and tell the user what to expect if they follow the link.

1. Describe what the link is for

Keep the link as short as possible while being descriptive.

  • Do this: Review the Links vs buttons page

    • Markdown: Review the [Links vs buttons page](URL)

    • Why is this OK? Because the link text includes the title of the page

  • Or this: Review VA guidance about links

    • Markdown: Review [VA guidance about links](URL)

    • Why is this OK? Because the link text specifies the subject matter of the page

  • Not this: Review VA guidance about links

    • Markdown: Review [VA guidance](URL) about links

    • Why not?  Because the link text doesn’t specify the subject of the VA guidance

2. Provide context

The link must be understandable on its own without any of the surrounding content.

  • Do this: Figure 1 - quotes about the user interface

    • Markdown:  [Figure 1 - quotes about the user interface](URL)

    • Why is this OK? Because the link text contains the context

  • Not this: Figure 1 (quotes about the user interface)

    • Markdown: [Figure 1](URL) (quotes about the user interface)

    • Why not? Because the “Figure 1” link doesn’t contain any context

Every link needs to be distinct from all other links on the page.

  • Do this:

    CODE
    [Edit personal information](URL)
    [Edit address](URL)
  • Not this:

    CODE
    Personal information: [Edit](URL)
    Address: [Edit](URL)
    • Why not? Because the links are identical and don’t tell you what you’re editing

4. Tell users if the link takes them to something that’s not a web page

If the link takes the user to a file (e.g., an image, PDF, or Word document), put that information in the link text.

  • Do this: Figure 1 - sample benefit letter (PDF)

    • Markdown: [Figure 1 - sample benefit letter (PDF)](URL)

  • Or this: Figure 1 - sample benefit letter (image)

    • Markdown: [Figure 1 - sample benefit letter (image)](URL)

  • Or this: Changed the XX button (Figure 2 shows the new YY button)

    • Markdown: Changed the XX button ([Figure 2 shows the new YY button](URL))

    • Why is this OK? Because the word “Figure” implies “image”

  • Or this: Screenshot of the magnification issue in Figure 3. 

    • Markdown: <details><summary>Screenshot of the magnification issue in Figure 3</summary>

    • Why is this OK? Because the word “screenshot” implies “image”

  • Not this: Figure 1 - sample benefit letter

    • Markdown: [Figure 1 - sample benefit letter](URL)

    • Why not? Because the link doesn’t specify that it’s linking to an image

Use disclosure widgets correctly

Markdown allows the use of <details> and <summary>. This creates a disclosure widget; the content within <summary> is the toggle button.

Example:

CODE
<details> 
<summary>My disclosure widget</summary>
Now it's open!
</details>
A disclosure widget. The toggle button says My disclosure widget. The closed and open states are displayed. The open state says Now it's open.

Disclosure widgets come with tradeoffs:

  • Long pages can be overwhelming to read and hard to scan. Disclosure widgets can reduce visual and mental clutter.

  • Users can miss information when it’s hidden in a disclosure widget.

  • Some assistive technologies don’t properly announce <details> and <summary> state changes, such as when the widget is open or closed.

It’s important to use disclosure widgets thoughtfully and only when necessary. For example, in a research report, an illustrative screenshot could be placed in a disclosure widget if it impedes the report’s scannability or is tangential to the rest of the content. 

Before deciding to use a disclosure widget, ask yourself these questions:

  1. Does this information need to be on the page?

  2. If yes, does the information need to be hidden? Why?

  3. If yes, use a disclosure widget. Each use of <summary> should have a unique, meaningful name that describes the content and not the action required to open it (e.g., “click to open”).

    • Do this:

      CODE
      <details>
      <summary>Findings</summary>
      Content about findings
      </details>
      
      <details>
      <summary>Participant demographics</summary>
      Content about participant demographics
      </details>
      • Why is this OK? Because the <summary> is unique and descriptive for each disclosure widget

    • Not this:

      CODE
      <details>
      <summary>Details</summary>
      Content about findings
      </details>
      
      <details>
      <summary>Details</summary>
      Content about participant demographics
      </details>
      • Why not? Because the <summary> is identical for the two disclosure widgets

    • Do this:

      CODE
      <details>
      <summary>Screenshot of the link magnification issue in Figure 3</summary>
      Content
      </details>
    • Not this:

      CODE
      <details>
      <summary>Click to see a screenshot of the link magnification issue in Figure 3</summary>
      Content
      </details>
      • Why not? Because words like “click”, “expand”, “reveal”, and “show” duplicate the state information already announced by screen readers.

Use anchor links in long documents

It can be helpful to add anchor links to long documents to help users jump to the specific section they’re interested in. Think of these like an in-page table of contents:

A table of contents. The heading reads Jump to. The links read Hypotheses and conclusions, Key findings, Recommendations, Next Steps, Further research needed, Appendix, and Who we talked to.

GitHub automatically generates section heading links (e.g., #key-findings for ## Key findings). However, due to a GitHub bug, these links aren’t accessible because they don’t move focus to the heading when navigating by keyboard. To accommodate this, we recommend linking to the “chain link” icon rather than the heading itself.

Follow these steps to create a set of accessible anchor links in a GitHub-rendered Markdown file:

  1. Create your content using semantic headings (#, ##, etc.)

  2. Publish the page

  3. Find the anchor you want to link to:

    1. Tab to or hover over the heading you want to make a link for. You’ll notice a “chain link” icon:

      A user interface. A heading says Research Goals. This is preceded by an icon of two chains in a chain link representing a hyperlink.
    2. Select the icon. In the URL bar, copy what comes after the pound sign: ...research-report.md#key-findings.

    3. Add “user-content-” before that: #user-content-key-findings, in this example.

  4. Once you have all the anchors you want to link to, create a bulleted list near the top of your document. Link to the anchor link constructed in step 3. Use the heading text as the link text:

    - [Key findings](#user-content-key-findings)
    - [Recommendations](#user-content-recommendations)


Help and feedback

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.