diff --git a/src/components/common/RedactableValue.stories.tsx b/src/components/common/RedactableValue.stories.tsx
new file mode 100644
index 0000000..e39fda9
--- /dev/null
+++ b/src/components/common/RedactableValue.stories.tsx
@@ -0,0 +1,26 @@
+import React, { ReactElement } from "react";
+import { RedactableValue } from "./RedactableValue";
+
+export default {
+ title: "RedactableValue/RedactableValue",
+ component: RedactableValue,
+};
+
+export const RedactableValueDefault = (): ReactElement => {
+ return ;
+};
+
+export const RedactableValueIconDefault = (): ReactElement => {
+ return console.log("Please redact")} />;
+};
+
+export const RedactableValueIconCustom = (): ReactElement => {
+ return (
+ console.log("Please redact")}
+ iconRedact={<>X>}
+ />
+ );
+};
diff --git a/src/components/common/RedactableValue.test.tsx b/src/components/common/RedactableValue.test.tsx
new file mode 100644
index 0000000..3f519e4
--- /dev/null
+++ b/src/components/common/RedactableValue.test.tsx
@@ -0,0 +1,46 @@
+import React from "react";
+import { RedactableValue } from "./RedactableValue";
+import { screen, render, fireEvent } from "@testing-library/react";
+
+describe("redactablevalue component", () => {
+ it("should display value only when editable is not set", () => {
+ const callback = jest.fn();
+ render();
+
+ expect(screen.getByText("Text to display")).toBeInTheDocument();
+ expect(screen.queryByTitle("Redact handler")).not.toBeInTheDocument();
+ });
+
+ it("should display value only when editable is set to false", () => {
+ const callback = jest.fn();
+ render();
+
+ expect(screen.getByText("Text to display")).toBeInTheDocument();
+ expect(screen.queryByTitle("Redact handler")).not.toBeInTheDocument();
+ });
+
+ it("should display value, redact default icon and call onRedactionRequested when editable is set to true", () => {
+ const callback = jest.fn();
+ render();
+
+ expect(screen.getByText("Text to display")).toBeInTheDocument();
+ expect(screen.queryByTitle("Redact handler")).toBeInTheDocument();
+ expect(screen.queryByTitle("Redact default icon")).toBeInTheDocument();
+ fireEvent.click(screen.getByTitle("Redact handler"));
+ expect(callback).toHaveBeenCalledTimes(1);
+ });
+
+ it("should display value, custom icon redact and call onRedactionRequested when editable is set to true", () => {
+ const callback = jest.fn();
+ render(
+ foobar>} />
+ );
+
+ expect(screen.getByText("Text to display")).toBeInTheDocument();
+ expect(screen.queryByTitle("Redact handler")).toBeInTheDocument();
+ expect(screen.queryByTitle("Redact default icon")).not.toBeInTheDocument();
+ expect(screen.getByText("foobar")).toBeInTheDocument();
+ fireEvent.click(screen.getByText("foobar"));
+ expect(callback).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/src/components/common/RedactableValue.tsx b/src/components/common/RedactableValue.tsx
new file mode 100644
index 0000000..aa6883c
--- /dev/null
+++ b/src/components/common/RedactableValue.tsx
@@ -0,0 +1,66 @@
+import React, { FunctionComponent, useState } from "react";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faTimes } from "@fortawesome/free-solid-svg-icons";
+import styled from "@emotion/styled";
+import { noop } from "../../utils";
+
+const IconRedactStyled = styled.span`
+ transition: color 0.2s ease-out;
+ color: #dc2626; // text-red-600 (tailwind)
+
+ &:hover {
+ color: #b91c1c; // text-red-700 (tailwind)
+ }
+`;
+
+const IconRedact: FunctionComponent = () => {
+ return (
+
+
+
+ );
+};
+
+export interface RedactValueProps {
+ value?: string | number;
+ onRedactionRequested?: () => void;
+ editable?: boolean;
+ iconRedact?: React.ReactElement;
+}
+
+/**
+ * RedactableValue component is almost a duplicate of ObfuscatableValue component
+ * ObfuscatableValue component started from OpenCerts, and may be in use on existing certificates, hence we do not want to meddle with the existing functionality
+ * RedactableValue component displays a value and a cross when editable props is set to true, allows custom redact icon, hints at redacted values
+ */
+export const RedactableValue: FunctionComponent = ({
+ value,
+ onRedactionRequested = noop,
+ editable = false,
+ iconRedact = ,
+}) => {
+ const [isRedacted, setRedacted] = useState(false);
+
+ if (isRedacted) return **Redacted**;
+ if (!value) return **Field value does not exists**;
+
+ return (
+ <>
+ {value}
+ {editable && (
+ {
+ if (editable) {
+ onRedactionRequested();
+ setRedacted(true);
+ }
+ }}
+ >
+ {iconRedact}
+
+ )}
+ >
+ );
+};
diff --git a/src/index.tsx b/src/index.tsx
index f1422de..473a63c 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,5 +1,6 @@
export { FrameConnector } from "./components/frame/FrameConnector";
export { ObfuscatableValue } from "./components/common/ObfuscatableValue";
+export { RedactableValue } from "./components/common/RedactableValue";
export { FramedDocumentRenderer } from "./components/renderer/FramedDocumentRenderer";
export * from "./components/renderer/NoAttachmentRenderer";
export * from "./components/renderer/FullAttachmentRenderer";