React Native/Expo components and hooks for AppClerk compliance infrastructure
npm install appclerk-core appclerk-react-native react-native-markdown-display react-native-webviewnpx expo install appclerk-core appclerk-react-native react-native-markdown-display react-native-webviewNote: Use EXPO_PUBLIC_ prefix for environment variables in Expo projects.
// App.tsx
import { AppClerkProvider } from 'appclerk-react-native';
export default function App() {
return (
<AppClerkProvider
apiKey={process.env.APPCLERK_API_KEY}
projectId={process.env.APPCLERK_PROJECT_ID}
>
<YourApp />
</AppClerkProvider>
);
}import { PrivacyPolicy, TermsOfService } from 'appclerk-react-native';
import { View } from 'react-native';
export function SettingsScreen() {
return (
<View>
<PrivacyPolicy renderMode="native" />
<TermsOfService renderMode="native" />
</View>
);
}Required context provider that wraps your app. Must be placed at the root of your component tree.
interface AppClerkProviderProps {
/** Your AppClerk API key (required) */
apiKey: string;
/** Your AppClerk project ID (required) */
projectId: string;
/** Custom API URL (optional, defaults to https://appclerk.dev/api/v1) */
apiUrl?: string;
/** Enable debug logging (optional) */
debug?: boolean;
/** Cache TTL in milliseconds (optional) */
cacheTtl?: number;
/** Maximum retry attempts (optional) */
maxRetries?: number;
/** React children */
children: React.ReactNode;
}Component for displaying privacy policy documents. Supports both native markdown rendering and webview modes.
import { PrivacyPolicy } from 'appclerk-react-native';
<PrivacyPolicy
renderMode="native" // "native" | "webview"
displayMode="inline" // "inline" | "modal"
theme="auto" // "light" | "dark" | "auto"
showHeader={true} // Show document header
showFooter={false} // Show footer
cachePolicy="cache-first" // "cache-first" | "network-only" | "cache-only"
onError={(error) => {}} // Error callback
onClose={() => {}} // Close callback (for modal mode)
/>Component for displaying terms of service documents. Same props as PrivacyPolicy.
import { TermsOfService } from 'appclerk-react-native';
<TermsOfService
renderMode="native"
displayMode="modal"
theme="dark"
/>Component for displaying detailed compliance status, including score, issues, and document statuses.
import { ComplianceStatus } from 'appclerk-react-native';
<ComplianceStatus
showDetails={true} // Show detailed issues and documents
showScore={true} // Show compliance score
refreshInterval={60000} // Auto-refresh interval in ms
onIssuePress={(issue) => {}} // Callback when issue is pressed
theme="auto" // "light" | "dark" | "auto"
/>Generic component for viewing any document type. Use PrivacyPolicy or TermsOfService for convenience, or DocumentViewer for custom document types.
import { DocumentViewer } from 'appclerk-react-native';
<DocumentViewer
documentType="privacy-policy" // "privacy-policy" | "terms-conditions" | etc.
renderMode="native"
displayMode="inline"
/>Access the AppClerk SDK instance directly. Useful for custom implementations or when you need more control.
import { useAppClerk } from 'appclerk-react-native';
function MyComponent() {
const appclerk = useAppClerk();
const handleFetch = async () => {
const doc = await appclerk.getDocumentMarkdown("privacy-policy");
console.log(doc.content);
};
return <Button onPress={handleFetch}>Fetch Document</Button>;
}Hook for fetching document markdown content. Automatically handles loading and error states.
import { useDocumentContent } from 'appclerk-react-native';
import { View, Text, ActivityIndicator } from 'react-native';
function MyComponent() {
const { data, loading, error } = useDocumentContent({
documentType: 'privacy-policy',
cachePolicy: 'cache-first',
});
if (loading) return <ActivityIndicator />;
if (error) return <Text>Error: {error.message}</Text>;
if (!data) return null;
return <Text>{data.content}</Text>;
}Hook for fetching document metadata without the full content.
import { useDocumentMetadata } from 'appclerk-react-native';
function MyComponent() {
const { data, loading } = useDocumentMetadata({
documentType: 'privacy-policy',
});
if (loading) return <Text>Loading...</Text>;
return (
<View>
<Text>Title: {data?.title}</Text>
<Text>Last Updated: {data?.lastUpdated}</Text>
<Text>Version: {data?.version}</Text>
</View>
);
}Hook for fetching compliance status. Supports auto-refresh via refreshInterval.
import { useComplianceStatus } from 'appclerk-react-native';
function MyComponent() {
const { data, loading, error } = useComplianceStatus({
refreshInterval: 60000, // Refresh every minute
});
if (loading) return <Text>Loading...</Text>;
if (error) return <Text>Error: {error.message}</Text>;
return (
<View>
<Text>Score: {data?.score}%</Text>
<Text>Status: {data?.status}</Text>
<Text>Issues: {data?.issues.length}</Text>
</View>
);
}Renders markdown natively using react-native-markdown-display:
<PrivacyPolicy renderMode="native" theme="auto" />Loads hosted HTML in a WebView using react-native-webview:
<PrivacyPolicy renderMode="webview" />Displays the document directly in your component tree.
<PrivacyPolicy displayMode="inline" />Displays the document in a modal overlay. Requires an onClose callback.
<PrivacyPolicy
displayMode="modal"
onClose={() => setShowModal(false)}
/>AppClerk React Native SDK provides comprehensive styling options for all markdown elements. You can style every aspect of your legal documents using React Native's ViewStyle and TextStyle objects.
Use the style prop to style the document container:
<TermsOfService
style={{
padding: 20,
backgroundColor: "#ffffff",
borderRadius: 8,
}}
/>Use the textStyle prop to apply base text styles:
<TermsOfService
textStyle={{
fontSize: 16,
lineHeight: 24,
color: "#333333",
fontFamily: "System",
}}
/>Apply granular styles to all markdown elements using the customStyles prop:
<TermsOfService
customStyles={{
// Container styles
container: {
padding: 20,
backgroundColor: "#ffffff",
},
// Body/base text styles
body: {
fontSize: 16,
lineHeight: 24,
color: "#333333",
},
// Headings
h1: {
fontSize: 28,
fontWeight: "bold",
color: "#1a1a1a",
marginTop: 24,
marginBottom: 16,
},
h2: {
fontSize: 24,
fontWeight: "600",
color: "#2d2d2d",
marginTop: 20,
marginBottom: 12,
},
// Paragraphs
p: {
fontSize: 16,
lineHeight: 24,
color: "#4a4a4a",
marginBottom: 16,
},
// Lists
ul: {
marginBottom: 16,
paddingLeft: 20,
},
li: {
fontSize: 16,
lineHeight: 24,
color: "#4a4a4a",
marginBottom: 8,
},
// Links
a: {
color: "#007AFF",
textDecorationLine: "underline",
},
// Code
code: {
backgroundColor: "#f3f4f6",
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 4,
fontSize: 14,
fontFamily: "monospace",
},
}}
/>You can combine style, textStyle, and customStyles for maximum flexibility:
<TermsOfService
style={{
padding: 20,
backgroundColor: "#ffffff",
}}
textStyle={{
fontSize: 16,
fontFamily: "System",
}}
customStyles={{
h1: {
fontSize: 28,
fontWeight: "bold",
},
p: {
lineHeight: 26, // Overrides textStyle lineHeight
},
}}
/>The following markdown elements can be styled:
| Element | customStyles Key | Type |
|---|---|---|
| Container | container | ViewStyle |
| Body | body | TextStyle |
| Headings (h1-h6) | h1, h2, h3... or heading1, heading2... | TextStyle |
| Paragraph | p or paragraph | TextStyle |
| Lists | ul, ol, li or bullet_list, ordered_list, listItem | ViewStyle / TextStyle |
| Links | a or link | TextStyle |
| Code | code, pre or code_inline, code_block | TextStyle / ViewStyle |
<TermsOfService
theme="dark"
customStyles={{
container: {
backgroundColor: "#1f2937",
},
body: {
color: "#f9fafb",
},
h1: { color: "#ffffff" },
p: { color: "#d1d5db" },
a: { color: "#60a5fa" },
}}
/>import { Platform } from "react-native";
<TermsOfService
customStyles={{
h1: {
fontSize: Platform.OS === "ios" ? 28 : 26,
fontWeight: Platform.OS === "ios" ? "600" : "bold",
},
p: {
fontSize: Platform.OS === "ios" ? 16 : 15,
lineHeight: Platform.OS === "ios" ? 24 : 22,
},
}}
/>import { PrivacyPolicy, TermsOfService } from 'appclerk-react-native';
import { View, ScrollView, TouchableOpacity, Text } from 'react-native';
export function SettingsScreen() {
const [showPrivacy, setShowPrivacy] = useState(false);
const [showTerms, setShowTerms] = useState(false);
return (
<ScrollView>
<TouchableOpacity onPress={() => setShowPrivacy(true)}>
<Text>View Privacy Policy</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => setShowTerms(true)}>
<Text>View Terms of Service</Text>
</TouchableOpacity>
{showPrivacy && (
<PrivacyPolicy
displayMode="modal"
onClose={() => setShowPrivacy(false)}
/>
)}
{showTerms && (
<TermsOfService
displayMode="modal"
onClose={() => setShowTerms(false)}
/>
)}
</ScrollView>
);
}import { ComplianceStatus } from 'appclerk-react-native';
import { View } from 'react-native';
export function ComplianceScreen() {
return (
<View style={{ flex: 1 }}>
<ComplianceStatus
showDetails={true}
showScore={true}
refreshInterval={60000}
onIssuePress={(issue) => {
console.log('Issue:', issue);
// Navigate to issue details
}}
/>
</View>
);
}This package is fully compatible with Expo and works in both:
Environment Variables in Expo:
Use the EXPO_PUBLIC_ prefix for environment variables:
<AppClerkProvider
apiKey={process.env.EXPO_PUBLIC_APPCLERK_API_KEY}
projectId={process.env.EXPO_PUBLIC_APPCLERK_PROJECT_ID}
/>To use the SDK, you need an API key and project ID from your AppClerk dashboard.