# Links and Images

Course: [Markdown](https://www.devtutorials.ai/learn/markdown) · Section: Markdown Fundamentals
Source: https://www.devtutorials.ai/learn/markdown/fundamentals/links-and-images

> Write links and images that work. Fix three broken links, use relative links between project files and links to headings, keep long addresses in reference links, and write alt text that people and AI agents can use.

## Three Links That Went Nowhere

Ravi adds links to the order-support README. Each one points to a page in the `docs` folder. They look fine in his editor:

```md runnable title="Three broken links"
Read the [refund policy] (docs/refunds.md).

See [shipping times](docs/shipping times.md).

Ask the [help team][helpdesk].

[help-desk]: docs/help.md
```

Look at the Rendered tab. None of them is a link. Each one shows its brackets and its path as plain text. Open the HTML tab: there is not one `a` tag. `a` is the HTML tag for a link.

Each link broke for a different reason: a space in the wrong place, a space in the path, and a name that does not match. In this lesson, you will learn all three rules, and how to add pictures that every reader can understand.

**In simple words:** a link is text in square brackets, then a path in round brackets, with nothing in between.

## TL;DR

- A link is `[text](path)`. The text is what readers see. The path is where it goes.
- No space between `]` and `(`. No spaces inside the path, or wrap the path in `< >`.
- A **relative link** like `docs/refunds.md` points to another file in the same project.
- `#refund-window` links to a heading on the same page.
- An image is a link with `!` in front: `![alt text](path)`. The **alt text** describes the picture for people and tools that cannot see it.
- Link text should say where the link goes. Never write "click here".

## A Real-World Example

Think about a signpost at a crossroads.

A good sign says "Railway station, 2 km". You know where it goes before you walk. A bad sign just says "This way". You have to follow it to find out.

Links are signposts. The text in the square brackets is the sign. The path in the round brackets is the road. Write the sign so a reader knows where it leads without clicking.

## What You Will Learn

In this lesson, you will learn:

1. How to write a link, and the two spacing rules.
2. How relative links point to other files in a project.
3. How to link to a heading on the same page.
4. How reference links keep long paragraphs readable.
5. How to add an image, and how to write good alt text.
6. How to write link text that people and AI agents can use.

## Cheat Sheet

```md runnable title="Links and images"
A link: [refund policy](docs/refunds.md)

A link with a title: [refund policy](docs/refunds.md "Opens the refund policy")

A link to a heading: [refund window](#refund-window)

A web address: <https://commonmark.org>

A reference link: see the [shipping guide][ship].

[ship]: docs/shipping.md

An image:

![Refund flow: request, check, approve](/markdown-assets/refund-flow.svg)
```

Links in these boxes do not open when you click them, so you cannot leave the lesson by accident. Use the HTML tab to see where each one points.

## Writing a Link

### Text, Then Path

A **link** has two parts. The **link text** goes in square brackets. The **path** goes in round brackets, right after.

```md runnable title="One link, two parts"
Read the [refund policy](docs/refunds.md) before you approve a refund.
```

Open the HTML tab. The renderer made an `a` tag. The path went into `href`, which means "where this link goes". The link text is what sits between the tags.

### The Two Spacing Rules

Most broken links break one of two rules.

**Rule 1:** no space between `]` and `(`. With a space, Markdown sees normal brackets, not a link.

**Rule 2:** no spaces inside the path. A space ends the path early, so the link breaks. If a file name has a space, wrap the path in angle brackets, or write `%20` for each space.

```md runnable title="Fixing the spaces"
Broken: [refund policy] (docs/refunds.md)

Fixed: [refund policy](docs/refunds.md)

Broken: [shipping times](docs/shipping times.md)

Fixed: [shipping times](<docs/shipping times.md>)

Fixed: [shipping times](docs/shipping%20times.md)
```

Open the HTML tab. Both fixed versions of the shipping link point to `docs/shipping%20times.md`. `%20` is how a web address writes a space.

The best fix is a file name with no spaces at all. Use hyphens instead: `shipping-times.md`. Then every link to it is short and safe.

### A Title on Hover

You can add a **title** after the path, in quotes. Most browsers show it when you hold the mouse over the link.

```md runnable title="A link with a title"
Read the [refund policy](docs/refunds.md "Refund rules for support staff").
```

The HTML tab shows the title as a `title` attribute. A title is optional. Do not put important facts in it, because people on phones and keyboards never see it.

## Where a Link Can Go

### Relative Links

A **relative link** points to a file by its place in the project, not by a full web address. `docs/refunds.md` means "the file `refunds.md` inside the `docs` folder, next to this file".

Here is the order-support project:

```text title="The order-support project folder"
order-support/
├── README.md
└── docs/
    ├── refunds.md
    └── shipping.md
```

| From this file | To this file | Write |
|---|---|---|
| `README.md` | `docs/refunds.md` | `[Refunds](docs/refunds.md)` |
| `docs/refunds.md` | `docs/shipping.md` | `[Shipping](shipping.md)` |
| `docs/refunds.md` | `README.md` | `[Home](../README.md)` |

`../` means "go up one folder". GitHub and most docs sites follow relative links between `.md` files.

Relative links keep working when the project moves to a new address, or when someone downloads it. A full web address to your own repo breaks the moment the repo is renamed.

### Links to a Heading

A link that starts with `#` jumps to a heading on the same page. You met **anchors** in the last lesson. GitHub makes them from the heading text.

```md runnable title="Jump to a section"
Jump to the [refund window](#refund-window).

## Refund window

Refunds are allowed within 30 days.
```

To link to a heading in **another** file, put the anchor after the path: `[refund window](docs/refunds.md#refund-window)`.

### Web Addresses

For a full web address, use the same `[text](path)` form. If you want to show the address itself, wrap it in angle brackets.

```md runnable title="Web addresses three ways"
[CommonMark](https://commonmark.org)

<https://commonmark.org>

https://commonmark.org
```

All three are links in GitHub mode. Now switch the box to **CommonMark**. The last one is plain text. Turning a bare address into a link is a GitHub feature. Angle brackets work everywhere.

## Reference Links

### Keep the Paragraph Clean

Long web addresses in the middle of a sentence make the raw text hard to read. A **reference link** moves the address out of the way.

You write a short label in the sentence. You define the label once, on its own line, anywhere in the file.

```md runnable title="A reference link"
Refunds follow the [refund policy][refunds]. If a refund is late,
check the [refund policy][refunds] again, then ask the [help desk][help].

[refunds]: docs/refunds.md
[help]: https://example.com/help-desk
```

The two definition lines do not appear on the page. Both mentions of `[refunds]` became the same link. Change the path once, and both links change.

### The Label Must Match

The label in the sentence must match a definition. Capital letters do not matter. Spelling and hyphens do.

That is why the help team link at the top of the lesson broke. The sentence used `[helpdesk]`. The definition said `[help-desk]`. Go back up and make them the same.

A link with a missing label does not show an error. It quietly shows as text in brackets. Check the Rendered tab, or look for `a` tags in the HTML tab, every time you add a reference link.

## Images

### An Image Is a Link With `!`

An **image** uses the same form as a link, with a `!` in front. The text in the square brackets becomes the **alt text**: words that describe the picture.

```md runnable title="An image of the refund flow"
![Refund flow: request, check, approve](/markdown-assets/refund-flow.svg)
```

Open the HTML tab. The renderer made an `img` tag. The path went into `src`, the image source. The text went into `alt`.

### Why Alt Text Matters

The **alt text** is read out by screen readers for people who cannot see the picture. It is shown when the picture fails to load. And it is often the only part of a picture an AI agent gets: many agents read the text of a file, not the images.

| Alt text | Is it useful? |
|---|---|
| `![](refund-flow.svg)` | No. Empty, so the picture is invisible to screen readers and agents |
| `![image](refund-flow.svg)` | No. It says nothing about the picture |
| `![refund-flow.svg](refund-flow.svg)` | No. A file name is not a description |
| `![Refund flow: request, check, approve](refund-flow.svg)` | Yes. It says what the picture shows |

Write alt text as if you are describing the picture to someone on the phone. Keep it to one short sentence.

### Images and Size

Markdown has no way to set an image's size. If you need one, use an HTML `img` tag with a `width`. GitHub allows this. Some sites remove HTML, so use it only when you need it.

```md runnable title="An image with a size"
<img src="/markdown-assets/refund-flow.svg" alt="Refund flow: request, check, approve" width="240">
```

### A Picture That Is a Link

Put an image inside a link's square brackets to make the picture clickable.

```md runnable title="A clickable picture"
[![Refund flow: request, check, approve](/markdown-assets/refund-flow.svg)](docs/refunds.md)
```

Open the HTML tab. The `img` sits inside an `a`. A click on the picture would open `docs/refunds.md`.

## Link Text for People and Agents

Screen readers can list every link on a page. Search engines read link text to learn what a page is about. AI agents read the text in the brackets to decide which link to follow.

So the link text must make sense on its own, without the sentence around it.

```md runnable title="Bad and good link text"
For refunds, [click here](docs/refunds.md).

For refunds, read [this](docs/refunds.md).

Read the [refund policy](docs/refunds.md).
```

Only the last link says where it goes. A list of links reading "click here", "this" and "refund policy" is only useful for one of them.

In `AGENTS.md` and other agent files, link to the exact file an agent should read: `[testing guide](docs/testing.md)`. A clear name and a relative path tell the agent both what the file is and where to find it.

## Where Links Are Used

- **README files:** links to the docs folder, the licence and the contribution guide.
- **Docs sites:** links between pages, and to headings on long pages.
- **Agent files:** links to the files an agent should read for a task.
- **Specs and tickets:** links to designs, related tickets and evidence.
- **Release notes:** links to the pull request behind each change.

## Common mistakes

| Symptom | Cause | Fix |
|---|---|---|
| The link shows as `[text] (path)` in plain text | A space between `]` and `(` | Remove the space |
| The link shows in brackets, path and all | A space inside the path | Use a name with no spaces, wrap the path in `< >`, or write `%20` |
| A reference link shows as `[text][label]` | The label does not match any definition | Make the label and the definition the same |
| A link works on GitHub but not in another app | It is a bare web address | Wrap the address in `< >`, or use `[text](address)` |
| A link to another file is broken on GitHub | The relative path starts from the wrong folder | Count the folders from the file the link is in; use `../` to go up |
| A screen reader says nothing for an image | The alt text is empty | Describe the picture in the square brackets |
| A section link stopped working | The heading was renamed, so its anchor changed | Update every link that uses the old anchor |

## Quick Check

## Exercises

## What to Remember

- A link is `[text](path)`, with nothing between `]` and `(` and no spaces in the path.
- Relative links like `docs/refunds.md` and `../README.md` point to files in the same project.
- `#anchor` jumps to a heading. `file.md#anchor` jumps to a heading in another file.
- Reference links keep long addresses out of the sentence. The label must match its definition.
- An image is `![alt text](path)`. Always describe the picture in the alt text.
- Link text must say where the link goes. Never "click here".

## Further Reading

- [CommonMark: links](https://spec.commonmark.org/0.31.2/#links): every link form and its exact rules.
- [GitHub Docs: relative links and images](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes#relative-links-and-image-paths-in-readme-files): how GitHub follows links between files.
- [W3C: alt decision tree](https://www.w3.org/WAI/tutorials/images/decision-tree/): how to write alt text for any picture.

Next: **Code Blocks**, where you show commands and code exactly as typed, add language hints, and fix a code block that swallowed the rest of the document.
