diff --git a/packages/elements-react/src/tests/jest/test-utils.tsx b/packages/elements-react/src/tests/jest/test-utils.tsx
index 3f1cc96e3..589642f6f 100644
--- a/packages/elements-react/src/tests/jest/test-utils.tsx
+++ b/packages/elements-react/src/tests/jest/test-utils.tsx
@@ -7,11 +7,14 @@ import { OryProvider, OryProviderProps } from "../../context"
import { OryComponentProvider } from "../../context/component"
import { OryDefaultComponents } from "../../theme/default"
import { OryClientConfiguration } from "../../util"
+import { IntlProvider } from "../../context/intl-context"
const AllProviders = ({ children }: PropsWithChildren) => (
-
- {children}
-
+
+
+ {children}
+
+
)
const customRender = (
diff --git a/packages/elements-react/src/theme/default/components/form/checkbox.tsx b/packages/elements-react/src/theme/default/components/form/checkbox.tsx
index 2da0c0f5e..0437dcef0 100644
--- a/packages/elements-react/src/theme/default/components/form/checkbox.tsx
+++ b/packages/elements-react/src/theme/default/components/form/checkbox.tsx
@@ -4,14 +4,15 @@
"use client"
import { getNodeLabel } from "@ory/client-fetch"
import {
- OryNodeInputProps,
messageTestId,
+ OryNodeInputProps,
uiTextToFormattedMessage,
} from "@ory/elements-react"
import { useState } from "react"
import { useForm } from "react-hook-form"
import { useIntl } from "react-intl"
import { cn } from "../../utils/cn"
+import { CheckboxLabel } from "../ui/checkbox-label"
function CheckboxSVG() {
return (
@@ -82,7 +83,7 @@ export const DefaultCheckbox = ({
{node.messages.map((message) => (
+
+ Click here
+
+
+`;
+
+exports[`computeLabelElements renders a text with a single markdown link correctly 1`] = `
+
+`;
+
+exports[`computeLabelElements renders a text with link and extra text around it correctly 1`] = `
+
+ Click
+
+ here
+
+ to visit, or go elsewhere.
+
+`;
+
+exports[`computeLabelElements renders a text with multiple markdown links correctly 1`] = `
+
+`;
+
+exports[`computeLabelElements renders null if label is undefined 1`] = ``;
+
+exports[`computeLabelElements renders plain text without links correctly 1`] = `
+
+ This is just plain text
+
+`;
diff --git a/packages/elements-react/src/theme/default/components/ui/checkbox-label.spec.tsx b/packages/elements-react/src/theme/default/components/ui/checkbox-label.spec.tsx
new file mode 100644
index 000000000..1cfece1fc
--- /dev/null
+++ b/packages/elements-react/src/theme/default/components/ui/checkbox-label.spec.tsx
@@ -0,0 +1,56 @@
+import { render } from "../../../../tests/jest/test-utils"
+import { CheckboxLabel } from "./checkbox-label"
+
+describe("computeLabelElements", () => {
+ test("renders plain text without links correctly", () => {
+ const labelText = "This is just plain text"
+
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ })
+
+ test("renders a text with a single markdown link correctly", () => {
+ const labelText = "This is a [link](https://example.com)"
+
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ })
+
+ test("renders a text with multiple markdown links correctly", () => {
+ const labelText =
+ "This [first link](https://first.com) and this [second link](https://second.com)"
+
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ })
+
+ test("renders a text with link and extra text around it correctly", () => {
+ const labelText =
+ "Click [here](https://example.com) to visit, or go elsewhere."
+
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ })
+
+ test("handles a label with no text but a link", () => {
+ const labelText = "[Click here](https://example.com)"
+
+ const { container } = render(
+ ,
+ )
+ expect(container).toMatchSnapshot()
+ })
+
+ test("renders null if label is undefined", () => {
+ const { container } = render()
+ expect(container).toMatchSnapshot()
+ })
+})
diff --git a/packages/elements-react/src/theme/default/components/ui/checkbox-label.tsx b/packages/elements-react/src/theme/default/components/ui/checkbox-label.tsx
new file mode 100644
index 000000000..eb7a1d850
--- /dev/null
+++ b/packages/elements-react/src/theme/default/components/ui/checkbox-label.tsx
@@ -0,0 +1,64 @@
+import { UiText } from "@ory/client-fetch"
+import { useIntl } from "react-intl"
+import { uiTextToFormattedMessage } from "../../../../util"
+
+type CheckboxLabelProps = {
+ label?: UiText
+}
+
+const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g
+
+export function computeLabelElements(labelText: string) {
+ const elements = []
+ let lastIndex = 0
+
+ // Use matchAll to find all markdown links
+ for (const match of labelText.matchAll(linkRegex)) {
+ const linkText = match[1]
+ const url = match[2]
+ const matchStart = match.index
+ if (typeof matchStart === "undefined") {
+ // Some types seem to be wrong somewhere, eslint complains that matchStart can be undefined, but it can't?
+ // So we just skip this match, if it is undefined
+ continue
+ }
+
+ // Push the text before the match
+ if (matchStart > lastIndex) {
+ elements.push(labelText.slice(lastIndex, matchStart))
+ }
+
+ // Push the tag for the markdown link
+ elements.push(
+
+ {linkText}
+ ,
+ )
+
+ // Update lastIndex to the end of the current match
+ lastIndex = matchStart + match[0].length
+ }
+
+ // Push any remaining text after the last match
+ if (lastIndex < labelText.length) {
+ elements.push(labelText.slice(lastIndex))
+ }
+ return elements
+}
+
+export function CheckboxLabel({ label }: CheckboxLabelProps) {
+ const intl = useIntl()
+ if (!label) {
+ return null
+ }
+
+ const labelText = uiTextToFormattedMessage(label, intl)
+
+ return <>{computeLabelElements(labelText)}>
+}