diff --git a/packages/docs/src/routes/api/qwik-city/index.mdx b/packages/docs/src/routes/api/qwik-city/index.mdx
index db175d19d9f..ff7c8081b7c 100644
--- a/packages/docs/src/routes/api/qwik-city/index.mdx
+++ b/packages/docs/src/routes/api/qwik-city/index.mdx
@@ -2,7 +2,7 @@
title: \@builder.io/qwik-city API Reference
---
-# [API](/api) › @builder.io/qwik-city
+# [API](/api) → @builder.io/qwik-city
## Action
@@ -2617,3 +2617,45 @@ zodQrl: ZodConstructorQRL;
```
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/runtime/src/server-functions.ts)
+
+## Retrieving Headings with `useContent`
+
+The `useContent` hook is a powerful utility in Qwik City that allows you to access the content state of the current page. One of its key features is the ability to retrieve all the headings from `.mdx` files. This is particularly useful for generating sidebar links or a table of contents for the current page.
+
+### Example: Generating Sidebar Links
+
+Here's an example of how you can use `useContent` to retrieve and display the headings of the current `.mdx` page:
+
+```tsx
+import { component$, useContent } from '@builder.io/qwik';
+
+export const Sidebar = component$(() => {
+ const content = useContent();
+
+ return (
+
+ );
+});
+```
+
+### Notes
+- The `useContent` hook only works with `.mdx` files. It does not retrieve headings from `.tsx` files.
+- The `headings` property contains an array of objects, each representing a heading with the following structure:
+ - `id`: The unique identifier for the heading.
+ - `text`: The text content of the heading.
+ - `level`: The heading level (e.g., `1` for `
`, `2` for `
`, etc.).
+
+### When to Use
+This feature is particularly useful for:
+- Creating a dynamic table of contents for documentation pages.
+- Building sidebar navigation for blog posts or articles.
+
+For more details, refer to the [`useContent` API documentation](https://qwik.dev/docs/api/#usecontent).
diff --git a/packages/docs/src/routes/docs/(qwikcity)/guides/mdx/index.mdx b/packages/docs/src/routes/docs/(qwikcity)/guides/mdx/index.mdx
index cb09d66335c..b7b42a778dc 100644
--- a/packages/docs/src/routes/docs/(qwikcity)/guides/mdx/index.mdx
+++ b/packages/docs/src/routes/docs/(qwikcity)/guides/mdx/index.mdx
@@ -210,3 +210,72 @@ The `headings` array includes data about a markdown file's `
` to `
` [htm
Menus are contextual data declared with `menu.md` files. See [menus file definition](/docs/(qwikcity)/advanced/menu/index.mdx) for more information on the file format and location.
+# [API](/api) → @builder.io/qwik-city
+
+## Action
+
+```typescript
+export type Action<
+ RETURN,
+ INPUT = Record,
+ OPTIONAL extends boolean = true,
+> = {
+ (): ActionStore;
+};
+```
+
+**References:** [ActionStore](#actionstore)
+
+[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-city/src/runtime/src/types.ts)
+
+## ActionConstructor
+
+```typescript
+export type ActionConstructor = {
+ <
+ OBJ extends Record | void | null,
+ VALIDATOR extends TypedDataValidator,
+ REST extends [DataValidator, ...DataValidator[]],
+ >(
+ actionQrl: (
+ data: GetValidatorOutputType,
+ event: RequestEventAction,
+ ) => ValueOrPromise,
+ options: {
+ readonly id?: string;
+ readonly validation: [VALIDATOR, ...REST];
+ },
+ ): Action<
+ StrictUnion<
+ | OBJ
+ | FailReturn>>
+ | FailReturn>
+ >,
+ GetValidatorInputType,
+ false
+ >;
+ <
+ OBJ extends Record | void | null,
+ VALIDATOR extends TypedDataValidator,
+ REST extends [DataValidator, ...DataValidator[]],
+ >(
+ actionQrl: (
+ data: GetValidatorOutputType,
+ event: RequestEventAction,
+ ) => ValueOrPromise,
+ options: {
+ readonly id?: string;
+ readonly validation: [VALIDATOR, ...REST];
+ },
+ ): Action<
+ StrictUnion<
+ | OBJ
+ | FailReturn>>
+ | FailReturn>
+ >,
+ GetValidatorInputType,
+ true
+ >;
+};
+```
+
diff --git a/packages/docs/src/routes/docs/guides/mdx/use-content-headings.mdx b/packages/docs/src/routes/docs/guides/mdx/use-content-headings.mdx
new file mode 100644
index 00000000000..66c6e45a961
--- /dev/null
+++ b/packages/docs/src/routes/docs/guides/mdx/use-content-headings.mdx
@@ -0,0 +1,171 @@
+---
+title: Dynamic Page Navigation with MDX
+description: Learn how to create dynamic table of contents and navigation using MDX headings in Qwik City
+---
+
+# Dynamic Page Navigation with MDX
+
+When working with documentation or content-heavy pages in Qwik City, you often need to generate a table of contents or sidebar navigation based on the page's content. Qwik City provides a built-in solution for this through the `useContent()` hook, which can automatically extract headings from your MDX files.
+
+## Using `useContent()` for Page Navigation
+
+The `useContent()` hook allows you to access metadata about your current MDX page, including all its headings. This is particularly useful for:
+
+- Creating a table of contents for long articles
+- Building dynamic sidebar navigation
+- Implementing "jump to section" functionality
+- Generating progress indicators for article sections
+
+Here's a complete example of how to create a dynamic table of contents:
+
+```tsx
+import { component$, useContent } from '@builder.io/qwik';
+
+export const TableOfContents = component$(() => {
+ const content = useContent();
+
+ return (
+
+ );
+});
+```
+
+## Understanding the Headings Data
+
+The `headings` property from `useContent()` provides an array of heading objects with the following information:
+
+- `id`: The auto-generated ID for the heading (used for anchor links)
+- `text`: The actual text content of the heading
+- `level`: The heading level (1 for h1, 2 for h2, etc.)
+
+This only works with `.mdx` files - headings in `.tsx` files are not detected.
+
+## Common Use Cases
+
+### Progressive Disclosure Navigation
+
+You can create a collapsible navigation that shows the current section and its sub-sections:
+
+```tsx
+export const ProgressiveNav = component$(() => {
+ const content = useContent();
+ const currentSection = useSignal(null);
+
+ return (
+
+ );
+});
+```
+
+### Reading Progress Indicator
+
+You can combine heading information with scroll position to create a reading progress indicator:
+
+```tsx
+export const ReadingProgress = component$(() => {
+ const content = useContent();
+ const activeSection = useSignal('');
+
+ useOnWindow('scroll', $(() => {
+ const headingElements = content.headings?.map(h =>
+ document.getElementById(h.id)
+ ).filter(Boolean) || [];
+
+ const currentHeading = headingElements.find(el => {
+ const rect = el!.getBoundingClientRect();
+ return rect.top > 0 && rect.top < window.innerHeight / 2;
+ });
+
+ if (currentHeading) {
+ activeSection.value = currentHeading.id;
+ }
+ }));
+
+ return (
+
+ );
+});
+```
+
+## Tips and Best Practices
+
+1. **Consistent Heading Structure**: Maintain a logical heading hierarchy in your MDX files to ensure the navigation makes sense.
+
+2. **Performance**: The `useContent()` hook is optimized and won't cause unnecessary re-renders, so you can safely use it in navigation components.
+
+3. **Styling**: Consider using the heading level information to create visual hierarchy in your navigation:
+ ```css
+ .toc a {
+ /* Base styles */
+ }
+
+ /* Style based on heading level */
+ [data-level="1"] { font-size: 1.2em; font-weight: bold; }
+ [data-level="2"] { font-size: 1.1em; }
+ [data-level="3"] { font-size: 1em; }
+ ```
+
+4. **Accessibility**: Always ensure your dynamic navigation includes proper ARIA labels and keyboard navigation support.
+
+## Notes and Limitations
+
+- This functionality only works with `.mdx` files, not with `.tsx` or other file types
+- Headings must have unique content to generate unique IDs
+- The heading data is available only on the client-side after hydration
+- Consider using `useVisibleTask$` if you need to interact with the heading elements in the DOM
\ No newline at end of file