diff --git a/docs/contributing/pages/components.mdx b/docs/contributing/pages/components.mdx
index 7391c28af9767f..be654928387af8 100644
--- a/docs/contributing/pages/components.mdx
+++ b/docs/contributing/pages/components.mdx
@@ -37,6 +37,25 @@ An Alert component with no level setting will render as a Note component.
See also the [Note component](#note).
+## Expandable
+
+Render an expandable section.
+
+
+This is some content
+
+
+```markdown {tabTitle:Example}
+
+ This is some content
+
+```
+
+Attributes:
+
+- `title` (string)
+- `permalink` (boolean) - optional: the title as a link and show it in the TOC.
+
## Code Blocks
Consecutive code blocks will be automatically collapsed into a tabulated container. This behavior is generally useful if you want to define an example in multiple languages:
diff --git a/docs/platforms/javascript/common/session-replay/troubleshooting.mdx b/docs/platforms/javascript/common/session-replay/troubleshooting.mdx
index 59819f64731e02..4cfe10a2099bf9 100644
--- a/docs/platforms/javascript/common/session-replay/troubleshooting.mdx
+++ b/docs/platforms/javascript/common/session-replay/troubleshooting.mdx
@@ -20,7 +20,7 @@ excerpt: ""
description: "Troubleshooting Session Replay-specific Issues"
---
-
+
Canvas is supported in SDK versions >= `7.98.0`. Please see the canvas setup documention to get started with canvas recordings.
@@ -28,12 +28,12 @@ If you are on a supported SDK version and your `canvas` elements still aren't ge
-
+
The integration needs to enable `preserveDrawingBuffer` to export images from 3D and WebGL canvases. This can negatively affect canvas performance. If your canvas application is impacted by enabling `preserveDrawingBuffer`, you'll need to enable manual snapshotting and call a `snapshot()` method inside of your re-paint loop.
-
+
The replay 'video' is actually a video-like reproduction of the HTML on your website. This means that all the external resources your site uses (CSS/Images/Fonts), will be rendered by the corresponding <style>, <img> and <video> tags on your site. Add `sentry.io` to your CORS policy so the iframe hosted on sentry.io can fetch and display these resources.
@@ -46,7 +46,7 @@ Due to [browser limitations](https://developer.mozilla.org/en-US/docs/Web/SVG/El
-
+
By default, Replay will capture basic information about all outgoing fetch and XHR requests in your application. This includes the URL, request and response body size, method, and status code.
The intention is to limit the chance of collecting private data. You can configure the SDK to capture bodies and additional headers.
@@ -57,7 +57,7 @@ More details about this feature can be found in the
+
If you're experiencing slowdowns on your website, first make sure you're on the latest version of our SDK, which will have the most up-to-date bug fixes and performance improvements.
@@ -69,7 +69,7 @@ If you're having any problems with the latest SDK version, we want to hear about
-
+
Because of the complexity of the browser environment, there's a significant amount of code necessary in order for Session Replay to work. And while enabling Session Replay will add about 50 kb (gzipped) to your application bundle, we believe the benefits will outweigh the cost.
@@ -77,14 +77,14 @@ We're always working on ways to reduce the bundle size. Additionally, there are
-
+
The Sentry SDK attempts to minimize potential [performance overhead](/product/explore/session-replay/performance-overhead/#how-is-session-replay-optimized) in a few different ways. For example, by keeping track of the number of DOM mutations that are happening then disabling recording when a large number of changes are detected. Many simultaneous mutations can slow down a web page whether Session Replay is installed or not, but when a large number of mutations happen, the Replay client can incur an additional slowdown because it records each change.
If you're seeing the "A large number of mutations was detected" message while watching a replay, it means that your page could be optimized. For example, a dropdown list with thousands of entries could be refactored so that rows are virtualized where only the visible rows are rendered in the DOM. Another potential solution is to paginate the results fetch more data as the user scrolls through it. The SDK has a configuration that allows you to configure the limits before recording stops.
-
+
Our masking logic doesn't run on iframe content that's provided using the `srcdoc` attribute, rather than loaded in via `src`.
@@ -92,13 +92,13 @@ To hide this content, block the iframe, as described in our Session Replay
-
+
This is not a supported use-case. The replay package is built to work on a website and not as an externally-loaded script via browser extension or other mechanism. In fact, Sentry's Session Replay product can help developers find out when a third-party Chrome extension causes otherwise hard to debug or reproduce issues with their website.
-
+
Apollo Client sends an abort signal via `AbortController` whenever a query completes, to clean up and cancel all in-flight queries.
When this happens, the Replay can't capture the response body because the request is handled as aborted before Replay can access the response.
@@ -120,6 +120,6 @@ With this configuration, Replay is able to capture response bodies from Apollo C
-
+
Using the [`captureConsoleIntegration`](https://docs.sentry.io/platforms/javascript/configuration/integrations/captureconsole/) can cause replays to record as if you have triggered an exception. You can use [`beforeErrorSampling`](https://docs.sentry.io/platforms/javascript/guides/sveltekit/session-replay/understanding-sessions/#ignore-certain-errors-for-error-sampling) to avoid this behavior.
diff --git a/src/components/expandable.tsx b/src/components/expandable.tsx
index a07914d13b5952..03534b3259d342 100644
--- a/src/components/expandable.tsx
+++ b/src/components/expandable.tsx
@@ -1,12 +1,13 @@
'use client';
-import {ReactNode, useState} from 'react';
+import {ReactNode, useEffect, useState} from 'react';
import {ArrowDown} from 'react-feather';
import styled from '@emotion/styled';
type Props = {
children: ReactNode;
title: string;
+ permalink?: boolean;
};
type ExpandedProps = {
@@ -37,17 +38,56 @@ const ExpandableWrapper = styled.div`
padding: 0.5rem 1rem;
`;
-export function Expandable({title, children}: Props) {
+function slugify(str: string) {
+ return str
+ .toLowerCase()
+ .replace(/ /g, '-')
+ .replace(/[^a-z0-9-]/g, '');
+}
+
+const header = (title: string, permalink?: boolean) =>
+ permalink ? (
+