diff --git a/docs/capabilities/client/forms.mdx b/docs/capabilities/client/forms.mdx
index bd137e4b..b1801026 100644
--- a/docs/capabilities/client/forms.mdx
+++ b/docs/capabilities/client/forms.mdx
@@ -9,10 +9,7 @@ A form lets your app ask users to input and submit data. Forms can be defined wi
## Using forms
-
-
-
- **Promise-based forms:**
+**Promise-based forms:**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -64,104 +61,18 @@ A form lets your app ask users to input and submit data. Forms can be defined wi
}
```
- ### Parameters
-
- **`showForm(options)` → Returns Promise**
- - `form` (Form): The form specification object
- - `data` (FormValues, optional): Initial form field values
- - **Returns**: `Promise` - Resolves with form data or null if cancelled
-
-
-
- ```tsx
- import { Devvit, useState, useForm } from '@devvit/public-api';
-
- // Interactive post with form
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'FormExample',
- render: (context) => {
- const [name, setName] = useState('unknown');
-
- const myForm = useForm(
- {
- fields: [
- {
- type: 'string',
- name: 'name',
- label: 'Name',
- },
- ],
- },
- (values) => {
- // onSubmit handler
- setName(values.name);
- }
- );
-
- return (
-
- Hello {name}!
-
-
- );
- },
- });
-
- // Menu action with form
- const myForm = Devvit.createForm(
- {
- fields: [
- {
- type: 'string',
- name: 'food',
- label: 'What is your favorite food?',
- },
- ],
- },
- (event, context) => {
- // onSubmit handler
- context.ui.showToast({ text: event.values.food });
- }
- );
-
- Devvit.addMenuItem({
- label: 'Show a form',
- location: 'subreddit',
- onPress: async (_event, context) => {
- context.ui.showForm(myForm);
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
- ### Methods
+### Parameters
- **`context.ui.showForm(formConfig, onSubmit)`** - For interactive posts
- - `formConfig` (Form): The form specification object
- - `onSubmit` (function): Callback function when form is submitted
-
- **`Devvit.createForm(formConfig, onSubmit)`** - For menu actions
- - `formConfig` (Form): The form specification object
- - `onSubmit` (function): Callback function when form is submitted
-
-
-
+**`showForm(options)` → Returns Promise**
+- `form` (Form): The form specification object
+- `data` (FormValues, optional): Initial form field values
+- **Returns**: `Promise` - Resolves with form data or null if cancelled
## Menu response forms
For forms that open from a menu item, you can use menu responses. This is useful since you do not have access to the `@devvit/web/client` library from a menu item endpoint.
-
-
-
- **Configure forms in devvit.json:**
+**Configure forms in devvit.json:**
```json title="devvit.json"
{
"forms": {
@@ -316,57 +227,6 @@ For forms that open from a menu item, you can use menu responses. This is useful
-
-
-
- For Devvit Blocks, use the standard promise-based approach even in menu actions:
-
- ```tsx
- Devvit.addMenuItem({
- label: 'Multi-step workflow',
- location: 'subreddit',
- onPress: async (_event, context) => {
- // Step 1: Get user data from server
- const userData = await fetchUserData();
-
- // Step 2: Show form with server data
- const step1 = await context.ui.showForm({
- fields: [
- {
- type: 'string',
- name: 'name',
- label: 'Name',
- },
- ],
- data: { name: userData.name }
- });
-
- if (!step1) return;
-
- // Step 3: Save and continue to next form
- await saveUserName(step1.name);
-
- const step2 = await context.ui.showForm({
- fields: [
- {
- type: 'paragraph',
- name: 'review',
- label: 'How was your experience?',
- },
- ],
- });
-
- if (step2) {
- await saveReview(step2.review);
- context.ui.showToast('Thank you for your feedback!');
- }
- },
- });
- ```
-
-
-
-
## Form object
@@ -643,10 +503,7 @@ Below is a collection of common use cases and patterns.
### Dynamic forms
-
-
-
- **Client-side approach:**
+**Client-side approach:**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -775,56 +632,10 @@ Below is a collection of common use cases and patterns.
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- redditAPI: true,
- });
-
- const myForm = Devvit.createForm(
- (data) => {
- return {
- fields: [
- {
- type: 'string',
- name: 'username',
- label: 'Username',
- defaultValue: data.username,
- },
- ],
- // Adding `as const` helps you get accurate types in the onSubmit function below
- // This will only work if the function does not have any branching logic
- } as const;
- },
- (event, context) => {
- context.ui.showToast({
- text: `Hello ${event.values.username}`,
- });
- }
- );
-
- Devvit.addMenuItem({
- label: 'Show a dynamic form',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const user = await context.reddit.getCurrentUser();
- const username = user?.username;
- context.ui.showForm(myForm, { username });
- },
- });
- ```
-
-
### Multi-step forms
-
-
-
- **Client-side approach (Promise chaining):**
+**Client-side approach (Promise chaining):**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -1041,111 +852,12 @@ Below is a collection of common use cases and patterns.
-
-
- ```tsx
- import { Devvit, useState, useForm } from '@devvit/public-api';
-
- Devvit.configure({
- redditAPI: true,
- });
-
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'Multi-step Form',
- render: (context) => {
- const [name, setName] = useState('');
- const [food, setFood] = useState('');
- const [drink, setDrink] = useState('');
-
- const form3 = useForm(
- {
- fields: [
- {
- type: 'string',
- name: 'drink',
- label: "What's your favorite drink?",
- required: true,
- },
- ],
- },
- (values) => {
- setDrink(values.drink);
- }
- );
-
- const form2 = useForm(
- {
- fields: [
- {
- type: 'string',
- name: 'food',
- label: "What's your favorite food?",
- required: true,
- },
- ],
- },
- (values) => {
- setFood(values.food);
- context.ui.showForm(form3);
- }
- );
-
- const form1 = useForm(
- {
- fields: [
- {
- type: 'string',
- name: 'name',
- label: "What's your name?",
- required: true,
- },
- ],
- },
- (values) => {
- setName(values.name);
- context.ui.showForm(form2);
- }
- );
-
- function restart() {
- setName('');
- setFood('');
- setDrink('');
- context.ui.showForm(form1);
- }
-
- const isAnswered = name && food && drink;
-
- return (
-
- {isAnswered && (
- <>
- Name: {name}
- Favorite food: {food}
- Favorite drink: {drink}
-
-
- >
- )}
- {!isAnswered && }
-
- );
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
-
### One of everything
This example includes one of each of the [supported field types](#supported-fields-types).
-
-
-
- **Client-side approach:**
+**Client-side approach:**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -1386,83 +1098,10 @@ This example includes one of each of the [supported field types](#supported-fiel
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- const exampleForm = Devvit.createForm(
- {
- title: 'My favorites',
- description: 'Tell us about your favorite food!',
- fields: [
- {
- type: 'string',
- name: 'food',
- label: 'What is your favorite food?',
- helpText: 'Must be edible',
- required: true,
- },
- {
- label: 'About that food',
- type: 'group',
- fields: [
- {
- type: 'number',
- name: 'times',
- label: 'How many times a week do you eat it?',
- defaultValue: 1,
- },
- {
- type: 'paragraph',
- name: 'what',
- label: 'What makes it your favorite?',
- },
- {
- type: 'select',
- name: 'healthy',
- label: 'Is it healthy?',
- options: [
- { label: 'Yes', value: 'yes' },
- { label: 'No', value: 'no' },
- { label: 'Maybe', value: 'maybe' },
- ],
- defaultValue: ['maybe'],
- },
- ],
- },
- {
- type: 'boolean',
- name: 'again',
- label: 'Can we ask again?',
- },
- ],
- acceptLabel: 'Submit',
- cancelLabel: 'Cancel',
- },
- (event, context) => {
- console.log(event.values);
- context.ui.showToast('Thanks!');
- }
- );
-
- Devvit.addMenuItem({
- location: 'subreddit',
- label: 'One of everything form',
- onPress: (_event, context) => {
- context.ui.showForm(exampleForm);
- },
- });
- ```
-
-
### Image uploads
-
-
-
- **Client-side approach:**
+**Client-side approach:**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -1549,28 +1188,3 @@ This example includes one of each of the [supported field types](#supported-fiel
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- const form = Devvit.createForm(
- {
- title: 'Upload an image!',
- fields: [
- {
- name: 'myImage',
- type: 'image', // This tells the form to expect an image
- label: 'Image goes here',
- required: true,
- },
- ],
- },
- (event, context) => {
- // returns an i.redd.it URL
- const imageUrl = event.values.myImage;
- }
- );
- ```
-
-
diff --git a/docs/capabilities/client/menu-actions.mdx b/docs/capabilities/client/menu-actions.mdx
index c842d410..348944e8 100644
--- a/docs/capabilities/client/menu-actions.mdx
+++ b/docs/capabilities/client/menu-actions.mdx
@@ -11,10 +11,7 @@ Add an item to the three dot menu for posts, comments, or subreddits. Menu actio
**For most menu actions, use direct client effects.** These provide immediate responses and are perfect for simple actions that don't require server processing.
-
-
-
- **Menu items defined in devvit.json:**
+**Menu items defined in devvit.json:**
```json title="devvit.json"
{
@@ -74,53 +71,6 @@ app.post(
-
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
-// Simple menu action with direct client effects
-Devvit.addMenuItem({
-label: 'Show user info',
-location: 'post', // 'post', 'comment', 'subreddit', or array
-onPress: async (event, context) => {
-// Direct client effect - no server processing needed
- context.ui.showToast('Menu action clicked!');
-},
-});
-
-// Menu action with form
-const surveyForm = Devvit.createForm(
-{
-fields: [
-{
-type: 'string',
-name: 'feedback',
-label: 'Your feedback',
-},
-],
-},
-(event, context) => {
-// onSubmit handler
-context.ui.showToast({ text: `Thanks for the feedback: ${event.values.feedback}` });
-}
-);
-
-Devvit.addMenuItem({
-label: 'Quick survey',
-location: 'subreddit',
-forUserType: 'moderator', // Optional: restrict to moderators
-onPress: async (event, context) => {
-context.ui.showForm(surveyForm);
-},
-});
-
-````
-
-
-
-
## Supported contexts
You can decide where the menu action shows up by specifying the location property.
@@ -139,9 +89,6 @@ For moderator permission security, when opening a form from a menu action with `
In Devvit Web, your menu item should respond with a client side effect to give feedback to users. This is available as a UIResponse as you do not have access to the `@devvit/web/client` library from your server endpoints.
-
-
-
**Menu items with server processing:**
```json title="devvit.json"
@@ -242,45 +189,6 @@ app.post(
-
-
-
- For Devvit Blocks, use the direct context approach even for complex workflows:
-
-```tsx
-Devvit.addMenuItem({
- label: "Process and validate data",
- location: "post", // 'post', 'comment', 'subreddit', or array
- forUserType: "moderator", // Optional: restrict to moderators
- onPress: async (event, context) => {
- try {
- // Perform server-side processing
- const userData = await validateAndProcessData();
-
- // Show form with server-fetched data
- const result = await context.ui.showForm(
- {
- fields: [
- {
- type: "string",
- name: "processedData",
- label: "Processed Data",
- },
- ],
- },
- (values) => {
- context.ui.showToast(`Processed: ${values.processedData}`);
- },
- );
- } catch (error) {
- context.ui.showToast("Processing failed. Please try again.");
- }
- },
-});
-```
-
-
-
### Menu response examples
diff --git a/docs/capabilities/client/navigation.mdx b/docs/capabilities/client/navigation.mdx
index 3b143ed2..0a2cf3cb 100644
--- a/docs/capabilities/client/navigation.mdx
+++ b/docs/capabilities/client/navigation.mdx
@@ -1,6 +1,3 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Navigation
Use navigation functions to redirect users to Reddit content or external websites in response to user actions, such as button clicks. You can redirect to a `url` string or to objects such as [`Subreddit`](/api/redditapi/models/classes/Subreddit.md), [`Post`](/api/redditapi/models/classes/Post.md), or [`Comment`](/api/redditapi/models/classes/Comment.md).
@@ -13,135 +10,32 @@ When linking to Reddit content, the navigation function requires the app account
## Basic navigation
-
-
- ```ts title="client/index.ts"
- import { navigateTo } from '@devvit/web/client';
-
- // Navigate to external URLs
- navigateTo('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
-
- // Navigate to Reddit URLs
- navigateTo('https://www.reddit.com/r/movies/comments/tzxev3/');
-
- // Navigate to Reddit objects
- async function goToPost() {
- const post = await fetch('/api/getPost').then(r => r.json());
- navigateTo(post);
- }
-
- // Use in button handlers or user interactions
- function handleNavigateClick() {
- navigateTo('https://www.reddit.com/r/webdev');
- }
- ```
-
- ### Parameters
-
- **`navigateTo(target)`**
-
- - `target`: Either a URL string or a Reddit object (Subreddit, Post, Comment)
-
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({ redditAPI: true });
-
- // Navigate to URL
- Devvit.addMenuItem({
- label: 'Navigate to url',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const url = 'https://www.reddit.com/r/movies/comments/tzxev3/';
- context.ui.navigateTo(url);
- },
- });
-
- // Navigate to subreddit
- Devvit.addMenuItem({
- label: 'Navigate to subreddit',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const subredditId = 't5_2qh1o';
- const subreddit = await context.reddit.getSubredditById(subredditId);
- context.ui.navigateTo(subreddit);
- },
- });
-
- // Navigate to post
- Devvit.addMenuItem({
- label: 'Navigate to post',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const postId = 't3_tzxev3';
- const post = await context.reddit.getPostById(postId);
- context.ui.navigateTo(post);
- },
- });
-
- // Navigate to comment
- Devvit.addMenuItem({
- label: 'Navigate to comment',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const commentId = 't1_i426ob1';
- const comment = await context.reddit.getCommentById(commentId);
- context.ui.navigateTo(comment);
- },
- });
-
- // Interactive post with navigation
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'Navigation Post',
- render: (context) => {
- return (
-
-
-
- );
- },
- });
-
- // Menu action to create interactive post
- Devvit.addMenuItem({
- label: 'Add navigation post',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const subreddit = await context.reddit.getCurrentSubreddit();
- await context.reddit.submitPost({
- title: 'Navigate to post',
- subredditName: subreddit.name,
- preview: (
-
- Loading ...
-
- ),
- });
- context.ui.showToast('Created post!');
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
- ### Parameters
-
- **`context.ui.navigateTo(target)`**
-
- - `target`: Either a URL string or a Reddit object (Subreddit, Post, Comment)
-
-
-
+```ts title="client/index.ts"
+import { navigateTo } from '@devvit/web/client';
+
+// Navigate to external URLs
+navigateTo('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
+
+// Navigate to Reddit URLs
+navigateTo('https://www.reddit.com/r/movies/comments/tzxev3/');
+
+// Navigate to Reddit objects
+async function goToPost() {
+ const post = await fetch('/api/getPost').then(r => r.json());
+ navigateTo(post);
+}
+
+// Use in button handlers or user interactions
+function handleNavigateClick() {
+ navigateTo('https://www.reddit.com/r/webdev');
+}
+```
+
+### Parameters
+
+**`navigateTo(target)`**
+
+- `target`: Either a URL string or a Reddit object (Subreddit, Post, Comment)
:::tip Menu response navigation
For navigation in menu response workflows (when you need server processing before navigation), see the [Menu Actions](./menu-actions.mdx) documentation.
diff --git a/docs/capabilities/client/overview.mdx b/docs/capabilities/client/overview.mdx
index 72746638..5d645d5d 100644
--- a/docs/capabilities/client/overview.mdx
+++ b/docs/capabilities/client/overview.mdx
@@ -1,91 +1,35 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Client Overview
Client-side effects enable your Devvit app to provide interactive feedback and navigation to users. These effects include showing toasts, displaying forms, navigating to different pages, and more.
-
-
-
- Import client functions from `@devvit/web/client`:
-
- ```ts title="client/index.ts"
- import { showToast, showForm, navigateTo } from '@devvit/web/client';
-
- // Show a toast notification
- showToast('Hello from Devvit Web!');
-
- // Navigate to a URL
- navigateTo('https://www.reddit.com/r/webdev');
-
- // Show a form and handle response
- const result = await showForm({
- form: {
- fields: [
- {
- type: 'string',
- name: 'username',
- label: 'Username'
- }
- ]
- }
- });
-
- if (result) {
- console.log('Form submitted:', result.username);
+Import client functions from `@devvit/web/client`:
+
+```ts title="client/index.ts"
+import { showToast, showForm, navigateTo } from '@devvit/web/client';
+
+// Show a toast notification
+showToast('Hello from Devvit Web!');
+
+// Navigate to a URL
+navigateTo('https://www.reddit.com/r/webdev');
+
+// Show a form and handle response
+const result = await showForm({
+ form: {
+ fields: [
+ {
+ type: 'string',
+ name: 'username',
+ label: 'Username'
+ }
+ ]
}
- ```
-
-
-
-
- Use context methods in event handlers and component render functions:
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- // In a custom post component
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'Interactive Post',
- render: (context) => {
- return (
-
-
-
-
- );
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
-
-
+});
+
+if (result) {
+ console.log('Form submitted:', result.username);
+}
+```
## Available client effects
diff --git a/docs/capabilities/client/toasts.mdx b/docs/capabilities/client/toasts.mdx
index 6d94f099..a0ed6194 100644
--- a/docs/capabilities/client/toasts.mdx
+++ b/docs/capabilities/client/toasts.mdx
@@ -1,6 +1,3 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Toasts
Display temporary notification messages to users at the bottom of the screen.
@@ -24,108 +21,44 @@ Toasts will not work from scheduled jobs or triggers.
## Basic toast usage
-
-
- ```ts
- import { showToast } from '@devvit/web/client';
-
- // Simple text toast
- showToast('Operation completed successfully!');
-
- // Toast with custom appearance
- showToast({
- text: 'Data saved successfully!',
- appearance: 'success', // 'neutral' | 'success'
- });
-
- // Use in button handlers or user interactions
- function handleButtonClick() {
- try {
- // Perform some operation
- processUserData();
-
- showToast({
- text: 'Your data has been processed!',
- appearance: 'success'
- });
- } catch (error) {
- showToast('Something went wrong. Please try again.');
- }
+```ts
+import { showToast } from '@devvit/web/client';
+
+// Simple text toast
+showToast('Operation completed successfully!');
+
+// Toast with custom appearance
+showToast({
+ text: 'Data saved successfully!',
+ appearance: 'success', // 'neutral' | 'success'
+});
+
+// Use in button handlers or user interactions
+function handleButtonClick() {
+ try {
+ // Perform some operation
+ processUserData();
+
+ showToast({
+ text: 'Your data has been processed!',
+ appearance: 'success'
+ });
+ } catch (error) {
+ showToast('Something went wrong. Please try again.');
}
- ```
-
- ### Parameters
-
- **`showToast(textOrToast)`**
-
- - `textOrToast`: Either a string message or a `Toast` object
-
- **Toast Object Properties:**
-
- - `text` (string): The message to display
- - `appearance` (string, optional): The visual style (`'neutral'` | `'success'`). Defaults to `'neutral'`
-
-
-
- ```ts
- import { Devvit } from '@devvit/public-api';
-
- // Example with menu action
- Devvit.addMenuItem({
- label: 'Save Data',
- location: 'post',
- forUserType: 'moderator',
- onPress: async (event, context) => {
- try {
- // Perform some operation
- await performAction();
-
- // Show success toast
- context.ui.showToast({
- text: 'Data saved successfully!',
- appearance: 'success'
- });
- } catch (error) {
- // Show error toast
- context.ui.showToast('Something went wrong. Please try again.');
- }
- },
- });
-
- // Example in blocks
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'My Custom Post',
- render: (context) => {
- return (
-
-
-
- );
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
- ### Parameters
-
- **`context.ui.showToast(textOrToast)`**
-
- - `textOrToast`: Either a string message or a `Toast` object
-
- **Toast Object Properties:**
-
- - `text` (string): The message to display
- - `appearance` (string, optional): The visual style (`'neutral'` | `'success'`). Defaults to `'neutral'`
-
-
-
+}
+```
+
+### Parameters
+
+**`showToast(textOrToast)`**
+
+- `textOrToast`: Either a string message or a `Toast` object
+
+**Toast Object Properties:**
+
+- `text` (string): The message to display
+- `appearance` (string, optional): The visual style (`'neutral'` | `'success'`). Defaults to `'neutral'`
:::tip Menu response toasts
For toasts in menu response workflows (when you need server processing before showing toasts), see the [Menu Actions](./menu-actions.mdx) documentation.
diff --git a/docs/capabilities/server/cache-helper.mdx b/docs/capabilities/server/cache-helper.mdx
index c7724bfe..a6e4e5ce 100644
--- a/docs/capabilities/server/cache-helper.mdx
+++ b/docs/capabilities/server/cache-helper.mdx
@@ -14,56 +14,26 @@ Under the covers, it's Redis plus a local in-memory write-through cache. This pr
## Usage
-
-
- You can import cache helper from `@devvit/web/server` in your server source files. The cache helper is not available client-side, so you will see an error if you try to import it in client source files.
+You can import cache helper from `@devvit/web/server` in your server source files. The cache helper is not available client-side, so you will see an error if you try to import it in client source files.
- ```tsx
- import { cache } from '@devvit/web/server';
- ```
-
-
- You need to enable [Redis](../server/redis.mdx) in order to use Cache helper.
-
- ```tsx
- Devvit.configure({
- redis: true,
- // other capabilities
- });
- ```
-
-
+```tsx
+import { cache } from '@devvit/web/server';
+```
## Parameters
-The cache takes a key and a TTL regardless of whether you are using Devvit Web or Devvit Blocks. The only difference is that **the TTL is in seconds for Devvit Web** and **milliseconds for Devvit Blocks / Mod Tools**.
-
-
-
+The cache takes a key and a TTL:
| **Parameters** | **Description** |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `key` | This is a string that identifies a cached response. Instead of making a real request, the app gets the cached response with the key you provide. Make sure to use different keys for different data. For example, if you’re saving post-specific data, add the postId to the cache key, like this: `post_data_${postId})`. |
| `ttl` | Time to live is the number of **seconds** the cached response is expected to be relevant. Once the cached response expires, it will be voided and a real request is made to populate the cache again. You can treat it as a threshold, where ttl of 30 would mean that a request is done no more than once per 30 seconds. |
-
-
-
-| **Parameters** | **Description** |
-| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `key` | This is a string that identifies a cached response. Instead of making a real request, the app gets the cached response with the key you provide. Make sure to use different keys for different data. For example, if you’re saving post-specific data, add the postId to the cache key, like this: `post_data_${postId})`. |
-| `ttl` | Time to live is the number of **milliseconds** the cached response is expected to be relevant. Once the cached response expires, it will be voided and a real request is made to populate the cache again. You can treat it as a threshold, where ttl of 30000 would mean that a request is done no more than once per 30 seconds. |
-
-
-
-
## Example
Here’s a way to set up in-app caching instead of using scheduler or interval to fetch.
-
-
-
-
-
-
- ```tsx
- import { Devvit, useState } from '@devvit/public-api';
-
- Devvit.configure({
- redis: true,
- http: true, // to use `fetch()`
- // other capabilities
- });
-
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'Name',
- render: (context) => {
- const [data, setData] = useState({});
-
- async function getData() {
- const result = await context.cache(
- async () => {
- const response = await fetch('https://example.com');
- if (!response.ok) {
- throw Error(`HTTP error ${response.status}: ${response.statusText}`);
- }
- return await response.json();
- },
- {
- key: context.userId!,
- ttl: 10_000, // millis
- }
- );
-
- setData(result);
- }
-
- return (
-
-
-
- {data.something}
-
- );
- },
- });
-
- export default Devvit;
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
-
diff --git a/docs/capabilities/server/http-fetch.mdx b/docs/capabilities/server/http-fetch.mdx
index 3ea13c22..a3c024c3 100644
--- a/docs/capabilities/server/http-fetch.mdx
+++ b/docs/capabilities/server/http-fetch.mdx
@@ -1,6 +1,3 @@
-import Tabs from "@theme/Tabs";
-import TabItem from "@theme/TabItem";
-
# HTTP Fetch
Make requests to allow-listed external domains.
@@ -9,33 +6,17 @@ Your Devvit app can make network requests to access allow-listed external domain
## Enabling HTTP fetch calls
-
-
- ```json title="devvit.json"
- {
- ...
- "permissions": {
- "http": {
- "enable": true,
- "domains": ["my-site.com", "another-domain.net"]
- }
+```json title="devvit.json"
+{
+ ...
+ "permissions": {
+ "http": {
+ "enable": true,
+ "domains": ["my-site.com", "another-domain.net"]
}
}
- ```
-
-
- ```ts
- import { Devvit } from '@devvit/public-api';
-
-Devvit.configure({
-http: {
-domains: ['my-site.com', 'another-domain.net'],
-},
-});
-
-````
-
-
+}
+```
### Requesting a domain to be allow-listed
@@ -64,25 +45,22 @@ Apps must request each individual domain that it intends to fetch, even if the d
## Example usage
-
-
-
- Devvit Web applications have two different contexts for using fetch:
+Devvit Web applications have two different contexts for using fetch:
- ### Server-side fetch
+### Server-side fetch
- Server-side fetch allows your app to make HTTP requests to allowlisted external domains from your server-side code (e.g., API routes, server actions):
+Server-side fetch allows your app to make HTTP requests to allowlisted external domains from your server-side code (e.g., API routes, server actions):
```tsx title="server/index.ts"
- const response = await fetch('https://example.com/api/data', {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
- });
+const response = await fetch('https://example.com/api/data', {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+});
- const data = await response.json();
- console.log('External API response:', data);
+const data = await response.json();
+console.log('External API response:', data);
````
### Client-side fetch
@@ -98,7 +76,7 @@ Client-side fetch has different restrictions and can only make requests to your
```tsx title="client/index.ts"
const handleFetchData = async () => {
- // ✅ Correct: Fetching your own webview's API endpoint
+ // Correct: fetching your own webview's API endpoint
const response = await fetch("/api/user-data", {
method: "GET",
headers: {
@@ -110,51 +88,13 @@ const handleFetchData = async () => {
console.log("API response:", data);
};
-// ❌ Incorrect: Cannot fetch external domains from client-side
+// Incorrect: cannot fetch external domains from client-side
// const response = await fetch('https://external-api.com/data');
-// ❌ Incorrect: Endpoint must end with /api
+// Incorrect: endpoint must end with /api
// const response = await fetch('/user-data');
```
-
-
-
- For Devvit Blocks and Mod Tools, fetch is available within menu actions, triggers, and other server-side contexts:
-
- ```ts
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- http: {
- domains: ['example.com'],
- },
- });
-
- Devvit.addMenuItem({
- location: 'comment',
- label: 'Sample HTTP request',
- onPress: async (_event, context) => {
- console.log(`Comment ID: ${context.commentId}`);
- const response = await fetch('https://example.com', {
- method: 'post',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ content: context.commentId }),
- });
- context.ui.showToast(
- `Invoked HTTP request on comment: ${context.commentId}. Completed with status: ${response.status}`
- );
- },
- });
-
- export default Devvit;
- ```
-
-
-
-
## Troubleshooting
If you see the following error, it means HTTP Fetch requests are hitting the internal timeout limits. To resolve this:
diff --git a/docs/capabilities/server/media-uploads.mdx b/docs/capabilities/server/media-uploads.mdx
index 7316f1a7..b9e61a94 100644
--- a/docs/capabilities/server/media-uploads.mdx
+++ b/docs/capabilities/server/media-uploads.mdx
@@ -1,6 +1,3 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Media Uploads
:::warning
@@ -24,29 +21,16 @@ Enable the `media` permission in your `devvit.json` file.
## Using media uploads
On the server, you can pass the URL of any remotely hosted image (even if its not hosted on Reddit) to the `media.upload` function. This function will return a Reddit URL. Both HTTP and data URLs are supported.
-
-
- ```ts title="server/index.ts"
- import { media } from '@devvit/media';
- function submitImage() {
- const response = await media.upload({
- url: 'https://media2.giphy.com/media/xTiN0CNHgoRf1Ha7CM/giphy.gif',
- type: 'gif',
- });
- }
- ```
-
-
- ```ts
- import { Devvit } from '@devvit/public-api';
+```ts title="server/index.ts"
+import { media } from '@devvit/media';
+function submitImage() {
const response = await media.upload({
url: 'https://media2.giphy.com/media/xTiN0CNHgoRf1Ha7CM/giphy.gif',
type: 'gif',
});
- ```
-
-
+}
+```
## Canvas screenshots
diff --git a/docs/capabilities/server/reddit-api.mdx b/docs/capabilities/server/reddit-api.mdx
index cb9191ff..a2b32781 100644
--- a/docs/capabilities/server/reddit-api.mdx
+++ b/docs/capabilities/server/reddit-api.mdx
@@ -1,6 +1,3 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Reddit API Overview
The Reddit API allows you to read and write Reddit content such as posts / comments / upvotes, in order to integrate your app's behavior with the content of the community it's installed in.
@@ -24,32 +21,17 @@ Devvit apps cannot access certain private user data. This data is private to the
Here's how to obtain a reference to the Reddit client
-
-
- ```json title="devvit.json"
- {
- "permissions": {
- "reddit": true
- }
+```json title="devvit.json"
+{
+ "permissions": {
+ "reddit": true
}
- ```
- ```ts title="server/index.ts"
- import { reddit } from '@devvit/reddit';
- ```
-
-
- ```ts title="devvit.tsx"
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- redditAPI: true,
- });
+}
+```
- //Then, in any function that has a reference to Devvit.Context:
- const reddit = context.reddit;
- ```
-
-
+```ts title="server/index.ts"
+import { reddit } from '@devvit/reddit';
+```
## Reddit Thing IDs
@@ -79,9 +61,7 @@ const parentId = comment.parentId; // 't3_abc123' or 't1_def456'
## Example usage
### Submitting a post
-
-
- ```ts
+```ts
import { Devvit } from '@devvit/public-api';
import { context, reddit } from '@devvit/web/server';
@@ -100,36 +80,7 @@ export const createPost = async () => {
entry: 'default',
});
};
- ```
-
-
-
-```tsx
-import { Devvit } from '@devvit/public-api';
-
-Devvit.configure({
- redditAPI: true,
-});
-
-function createPost(context: Devvit.Context) {
- const currentSubreddit = context.reddit.getCurrentSubreddit();
- if (!currentSubreddit) {
- throw new Error('No subreddit found');
- }
-
- return context.reddit.submitPost({
- title: 'My custom post',
- subredditName: currentSubreddit.name,
- preview: (
-
- Loading...
-
- ),
- });
-}
```
-
-
### Submitting a comment
@@ -138,42 +89,19 @@ Auto-comments should be used to spark conversation in the post comments, but you
:::
-
-
- ```ts
- import { context, reddit } from '@devvit/web/server';
+```ts
+import { context, reddit } from '@devvit/web/server';
- export const createComment = async () => {
- const { subredditName } = context;
- if (!subredditName) {
- throw new Error('subredditName is required');
- }
+export const createComment = async () => {
+ const { subredditName } = context;
+ if (!subredditName) {
+ throw new Error('subredditName is required');
+ }
- reddit.submitComment({
- postId: 't3_123456', // Replace with the actual post ID
- text: 'This is a comment from a Devvit app',
- runAs: 'USER' // Optional: specify the user to run as
- });
- };
-```
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- redditAPI: true,
- });
-
- function createComment(context: Devvit.Context) {
- const { reddit } = context;
-
- reddit.submitComment({
- postId: 't3_123456', // Replace with the actual post ID
- text: 'This is a comment from a Devvit app',
- runAs: RunAs.USER, // Optional: specify the user to run as
- });
- };
+ reddit.submitComment({
+ postId: 't3_123456', // Replace with the actual post ID
+ text: 'This is a comment from a Devvit app',
+ runAs: 'USER' // Optional: specify the user to run as
+ });
+};
```
-
-
diff --git a/docs/capabilities/server/redis.mdx b/docs/capabilities/server/redis.mdx
index bcca403a..61a62107 100644
--- a/docs/capabilities/server/redis.mdx
+++ b/docs/capabilities/server/redis.mdx
@@ -30,9 +30,7 @@ All limits are applied at a per-installation granularity.
### Menu actions
-
-
- ```js title="devvit.json"
+```js title="devvit.json"
{
"menuActions": [
{
@@ -89,22 +87,6 @@ All limits are applied at a per-installation granularity.
-
-
- ```ts
- Devvit.addMenuItem({
- location: 'subreddit',
- label: 'Test Redis',
- onPress: async (event, { redis }) => {
- const key = 'hello';
- await redis.set(key, 'world');
- const value = await redis.get(key);
- console.log(`${key}: ${value}`);
- },
- });
- ```
-
-
### Games
@@ -117,11 +99,9 @@ You can take a look at this [Game Template](https://github.com/reddit/devvit-tem
Not all Redis features are supported. If you would like to request a specific Redis feature, please reach out to our team [via modmail](https://www.reddit.com/message/compose/?to=%2Fr%2FDevvit) or Discord.
:::
-For all examples below, we assume that you already have obtained a Redis Client. Here's how to obtain a Redis Client for Devvit Web, Devvit Blocks and Mod Tools:
+For all examples below, we assume that you already have obtained a Redis Client. Here's how to obtain a Redis Client:
-
-
- ```json title="devvit.json"
+```json title="devvit.json"
{
"permissions": {
"redis": true
@@ -131,20 +111,6 @@ For all examples below, we assume that you already have obtained a Redis Client.
```ts title="server/index.ts"
import { redis } from '@devvit/redis';
```
-
-
- ```ts title="devvit.tsx"
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- redis: true,
- });
-
- //Then, in any function that has a reference to Devvit.Context:
- const redis = context.redis;
- ```
-
-
### Simple read/write
diff --git a/docs/capabilities/server/triggers.mdx b/docs/capabilities/server/triggers.mdx
index f9be593c..409a6d18 100644
--- a/docs/capabilities/server/triggers.mdx
+++ b/docs/capabilities/server/triggers.mdx
@@ -39,9 +39,7 @@ A full list of events and their payloads can be found in the [EventTypes documen
### 1. Add triggers and endpoints to `devvit.json`
-
-
- Declare the triggers and their corresponding endpoints in your `devvit.json`:
+Declare the triggers and their corresponding endpoints in your `devvit.json`:
```json
"triggers": {
@@ -51,28 +49,10 @@ A full list of events and their payloads can be found in the [EventTypes documen
}
```
-
-
- Declare the triggers in your `devvit.json`:
-
-```json
-{
- "name": "your-app-name",
- "blocks": {
- "entry": "src/main.tsx",
- "triggers": ["onPostCreate"]
- }
-}
-```
-
-
-
### 2. Handle trigger events in your server logic
-
-
- Listen for the events in your server and access the data passed into the request:
+Listen for the events in your server and access the data passed into the request:
(
-
-
- Handle trigger events in your main file. Example (`src/main.tsx`):
-
-```tsx
-import { Devvit } from "@devvit/public-api";
-
-// Handling a PostSubmit event
-Devvit.addTrigger({
- event: "PostSubmit", // Event name from above
- onEvent: async (event) => {
- console.log(`Received OnPostSubmit event:\n${JSON.stringify(event)}`);
- },
-});
-
-// Handling multiple events: PostUpdate and PostReport
-Devvit.addTrigger({
- events: ["PostUpdate", "PostReport"], // An array of events
- onEvent: async (event) => {
- if (event.type == "PostUpdate") {
- console.log(`Received OnPostUpdate event:\n${JSON.stringify(request)}`);
- } else if (event.type === "PostReport") {
- console.log(`Received OnPostReport event:\n${JSON.stringify(request)}`);
- }
- },
-});
-
-export default Devvit;
-```
-
-
-
-
## Best practices
- Avoid creating recursive triggers that could cause infinite loops or crashes (for example, a comment trigger that creates a comment).
diff --git a/versioned_docs/version-0.12/capabilities/client/forms.mdx b/versioned_docs/version-0.12/capabilities/client/forms.mdx
index bd137e4b..b1801026 100644
--- a/versioned_docs/version-0.12/capabilities/client/forms.mdx
+++ b/versioned_docs/version-0.12/capabilities/client/forms.mdx
@@ -9,10 +9,7 @@ A form lets your app ask users to input and submit data. Forms can be defined wi
## Using forms
-
-
-
- **Promise-based forms:**
+**Promise-based forms:**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -64,104 +61,18 @@ A form lets your app ask users to input and submit data. Forms can be defined wi
}
```
- ### Parameters
-
- **`showForm(options)` → Returns Promise**
- - `form` (Form): The form specification object
- - `data` (FormValues, optional): Initial form field values
- - **Returns**: `Promise` - Resolves with form data or null if cancelled
-
-
-
- ```tsx
- import { Devvit, useState, useForm } from '@devvit/public-api';
-
- // Interactive post with form
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'FormExample',
- render: (context) => {
- const [name, setName] = useState('unknown');
-
- const myForm = useForm(
- {
- fields: [
- {
- type: 'string',
- name: 'name',
- label: 'Name',
- },
- ],
- },
- (values) => {
- // onSubmit handler
- setName(values.name);
- }
- );
-
- return (
-
- Hello {name}!
-
-
- );
- },
- });
-
- // Menu action with form
- const myForm = Devvit.createForm(
- {
- fields: [
- {
- type: 'string',
- name: 'food',
- label: 'What is your favorite food?',
- },
- ],
- },
- (event, context) => {
- // onSubmit handler
- context.ui.showToast({ text: event.values.food });
- }
- );
-
- Devvit.addMenuItem({
- label: 'Show a form',
- location: 'subreddit',
- onPress: async (_event, context) => {
- context.ui.showForm(myForm);
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
- ### Methods
+### Parameters
- **`context.ui.showForm(formConfig, onSubmit)`** - For interactive posts
- - `formConfig` (Form): The form specification object
- - `onSubmit` (function): Callback function when form is submitted
-
- **`Devvit.createForm(formConfig, onSubmit)`** - For menu actions
- - `formConfig` (Form): The form specification object
- - `onSubmit` (function): Callback function when form is submitted
-
-
-
+**`showForm(options)` → Returns Promise**
+- `form` (Form): The form specification object
+- `data` (FormValues, optional): Initial form field values
+- **Returns**: `Promise` - Resolves with form data or null if cancelled
## Menu response forms
For forms that open from a menu item, you can use menu responses. This is useful since you do not have access to the `@devvit/web/client` library from a menu item endpoint.
-
-
-
- **Configure forms in devvit.json:**
+**Configure forms in devvit.json:**
```json title="devvit.json"
{
"forms": {
@@ -316,57 +227,6 @@ For forms that open from a menu item, you can use menu responses. This is useful
-
-
-
- For Devvit Blocks, use the standard promise-based approach even in menu actions:
-
- ```tsx
- Devvit.addMenuItem({
- label: 'Multi-step workflow',
- location: 'subreddit',
- onPress: async (_event, context) => {
- // Step 1: Get user data from server
- const userData = await fetchUserData();
-
- // Step 2: Show form with server data
- const step1 = await context.ui.showForm({
- fields: [
- {
- type: 'string',
- name: 'name',
- label: 'Name',
- },
- ],
- data: { name: userData.name }
- });
-
- if (!step1) return;
-
- // Step 3: Save and continue to next form
- await saveUserName(step1.name);
-
- const step2 = await context.ui.showForm({
- fields: [
- {
- type: 'paragraph',
- name: 'review',
- label: 'How was your experience?',
- },
- ],
- });
-
- if (step2) {
- await saveReview(step2.review);
- context.ui.showToast('Thank you for your feedback!');
- }
- },
- });
- ```
-
-
-
-
## Form object
@@ -643,10 +503,7 @@ Below is a collection of common use cases and patterns.
### Dynamic forms
-
-
-
- **Client-side approach:**
+**Client-side approach:**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -775,56 +632,10 @@ Below is a collection of common use cases and patterns.
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- redditAPI: true,
- });
-
- const myForm = Devvit.createForm(
- (data) => {
- return {
- fields: [
- {
- type: 'string',
- name: 'username',
- label: 'Username',
- defaultValue: data.username,
- },
- ],
- // Adding `as const` helps you get accurate types in the onSubmit function below
- // This will only work if the function does not have any branching logic
- } as const;
- },
- (event, context) => {
- context.ui.showToast({
- text: `Hello ${event.values.username}`,
- });
- }
- );
-
- Devvit.addMenuItem({
- label: 'Show a dynamic form',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const user = await context.reddit.getCurrentUser();
- const username = user?.username;
- context.ui.showForm(myForm, { username });
- },
- });
- ```
-
-
### Multi-step forms
-
-
-
- **Client-side approach (Promise chaining):**
+**Client-side approach (Promise chaining):**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -1041,111 +852,12 @@ Below is a collection of common use cases and patterns.
-
-
- ```tsx
- import { Devvit, useState, useForm } from '@devvit/public-api';
-
- Devvit.configure({
- redditAPI: true,
- });
-
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'Multi-step Form',
- render: (context) => {
- const [name, setName] = useState('');
- const [food, setFood] = useState('');
- const [drink, setDrink] = useState('');
-
- const form3 = useForm(
- {
- fields: [
- {
- type: 'string',
- name: 'drink',
- label: "What's your favorite drink?",
- required: true,
- },
- ],
- },
- (values) => {
- setDrink(values.drink);
- }
- );
-
- const form2 = useForm(
- {
- fields: [
- {
- type: 'string',
- name: 'food',
- label: "What's your favorite food?",
- required: true,
- },
- ],
- },
- (values) => {
- setFood(values.food);
- context.ui.showForm(form3);
- }
- );
-
- const form1 = useForm(
- {
- fields: [
- {
- type: 'string',
- name: 'name',
- label: "What's your name?",
- required: true,
- },
- ],
- },
- (values) => {
- setName(values.name);
- context.ui.showForm(form2);
- }
- );
-
- function restart() {
- setName('');
- setFood('');
- setDrink('');
- context.ui.showForm(form1);
- }
-
- const isAnswered = name && food && drink;
-
- return (
-
- {isAnswered && (
- <>
- Name: {name}
- Favorite food: {food}
- Favorite drink: {drink}
-
-
- >
- )}
- {!isAnswered && }
-
- );
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
-
### One of everything
This example includes one of each of the [supported field types](#supported-fields-types).
-
-
-
- **Client-side approach:**
+**Client-side approach:**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -1386,83 +1098,10 @@ This example includes one of each of the [supported field types](#supported-fiel
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- const exampleForm = Devvit.createForm(
- {
- title: 'My favorites',
- description: 'Tell us about your favorite food!',
- fields: [
- {
- type: 'string',
- name: 'food',
- label: 'What is your favorite food?',
- helpText: 'Must be edible',
- required: true,
- },
- {
- label: 'About that food',
- type: 'group',
- fields: [
- {
- type: 'number',
- name: 'times',
- label: 'How many times a week do you eat it?',
- defaultValue: 1,
- },
- {
- type: 'paragraph',
- name: 'what',
- label: 'What makes it your favorite?',
- },
- {
- type: 'select',
- name: 'healthy',
- label: 'Is it healthy?',
- options: [
- { label: 'Yes', value: 'yes' },
- { label: 'No', value: 'no' },
- { label: 'Maybe', value: 'maybe' },
- ],
- defaultValue: ['maybe'],
- },
- ],
- },
- {
- type: 'boolean',
- name: 'again',
- label: 'Can we ask again?',
- },
- ],
- acceptLabel: 'Submit',
- cancelLabel: 'Cancel',
- },
- (event, context) => {
- console.log(event.values);
- context.ui.showToast('Thanks!');
- }
- );
-
- Devvit.addMenuItem({
- location: 'subreddit',
- label: 'One of everything form',
- onPress: (_event, context) => {
- context.ui.showForm(exampleForm);
- },
- });
- ```
-
-
### Image uploads
-
-
-
- **Client-side approach:**
+**Client-side approach:**
```ts title="client/index.ts"
import { showForm } from '@devvit/web/client';
@@ -1549,28 +1188,3 @@ This example includes one of each of the [supported field types](#supported-fiel
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- const form = Devvit.createForm(
- {
- title: 'Upload an image!',
- fields: [
- {
- name: 'myImage',
- type: 'image', // This tells the form to expect an image
- label: 'Image goes here',
- required: true,
- },
- ],
- },
- (event, context) => {
- // returns an i.redd.it URL
- const imageUrl = event.values.myImage;
- }
- );
- ```
-
-
diff --git a/versioned_docs/version-0.12/capabilities/client/menu-actions.mdx b/versioned_docs/version-0.12/capabilities/client/menu-actions.mdx
index c842d410..348944e8 100644
--- a/versioned_docs/version-0.12/capabilities/client/menu-actions.mdx
+++ b/versioned_docs/version-0.12/capabilities/client/menu-actions.mdx
@@ -11,10 +11,7 @@ Add an item to the three dot menu for posts, comments, or subreddits. Menu actio
**For most menu actions, use direct client effects.** These provide immediate responses and are perfect for simple actions that don't require server processing.
-
-
-
- **Menu items defined in devvit.json:**
+**Menu items defined in devvit.json:**
```json title="devvit.json"
{
@@ -74,53 +71,6 @@ app.post(
-
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
-// Simple menu action with direct client effects
-Devvit.addMenuItem({
-label: 'Show user info',
-location: 'post', // 'post', 'comment', 'subreddit', or array
-onPress: async (event, context) => {
-// Direct client effect - no server processing needed
- context.ui.showToast('Menu action clicked!');
-},
-});
-
-// Menu action with form
-const surveyForm = Devvit.createForm(
-{
-fields: [
-{
-type: 'string',
-name: 'feedback',
-label: 'Your feedback',
-},
-],
-},
-(event, context) => {
-// onSubmit handler
-context.ui.showToast({ text: `Thanks for the feedback: ${event.values.feedback}` });
-}
-);
-
-Devvit.addMenuItem({
-label: 'Quick survey',
-location: 'subreddit',
-forUserType: 'moderator', // Optional: restrict to moderators
-onPress: async (event, context) => {
-context.ui.showForm(surveyForm);
-},
-});
-
-````
-
-
-
-
## Supported contexts
You can decide where the menu action shows up by specifying the location property.
@@ -139,9 +89,6 @@ For moderator permission security, when opening a form from a menu action with `
In Devvit Web, your menu item should respond with a client side effect to give feedback to users. This is available as a UIResponse as you do not have access to the `@devvit/web/client` library from your server endpoints.
-
-
-
**Menu items with server processing:**
```json title="devvit.json"
@@ -242,45 +189,6 @@ app.post(
-
-
-
- For Devvit Blocks, use the direct context approach even for complex workflows:
-
-```tsx
-Devvit.addMenuItem({
- label: "Process and validate data",
- location: "post", // 'post', 'comment', 'subreddit', or array
- forUserType: "moderator", // Optional: restrict to moderators
- onPress: async (event, context) => {
- try {
- // Perform server-side processing
- const userData = await validateAndProcessData();
-
- // Show form with server-fetched data
- const result = await context.ui.showForm(
- {
- fields: [
- {
- type: "string",
- name: "processedData",
- label: "Processed Data",
- },
- ],
- },
- (values) => {
- context.ui.showToast(`Processed: ${values.processedData}`);
- },
- );
- } catch (error) {
- context.ui.showToast("Processing failed. Please try again.");
- }
- },
-});
-```
-
-
-
### Menu response examples
diff --git a/versioned_docs/version-0.12/capabilities/client/navigation.mdx b/versioned_docs/version-0.12/capabilities/client/navigation.mdx
index 3b143ed2..0a2cf3cb 100644
--- a/versioned_docs/version-0.12/capabilities/client/navigation.mdx
+++ b/versioned_docs/version-0.12/capabilities/client/navigation.mdx
@@ -1,6 +1,3 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Navigation
Use navigation functions to redirect users to Reddit content or external websites in response to user actions, such as button clicks. You can redirect to a `url` string or to objects such as [`Subreddit`](/api/redditapi/models/classes/Subreddit.md), [`Post`](/api/redditapi/models/classes/Post.md), or [`Comment`](/api/redditapi/models/classes/Comment.md).
@@ -13,135 +10,32 @@ When linking to Reddit content, the navigation function requires the app account
## Basic navigation
-
-
- ```ts title="client/index.ts"
- import { navigateTo } from '@devvit/web/client';
-
- // Navigate to external URLs
- navigateTo('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
-
- // Navigate to Reddit URLs
- navigateTo('https://www.reddit.com/r/movies/comments/tzxev3/');
-
- // Navigate to Reddit objects
- async function goToPost() {
- const post = await fetch('/api/getPost').then(r => r.json());
- navigateTo(post);
- }
-
- // Use in button handlers or user interactions
- function handleNavigateClick() {
- navigateTo('https://www.reddit.com/r/webdev');
- }
- ```
-
- ### Parameters
-
- **`navigateTo(target)`**
-
- - `target`: Either a URL string or a Reddit object (Subreddit, Post, Comment)
-
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({ redditAPI: true });
-
- // Navigate to URL
- Devvit.addMenuItem({
- label: 'Navigate to url',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const url = 'https://www.reddit.com/r/movies/comments/tzxev3/';
- context.ui.navigateTo(url);
- },
- });
-
- // Navigate to subreddit
- Devvit.addMenuItem({
- label: 'Navigate to subreddit',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const subredditId = 't5_2qh1o';
- const subreddit = await context.reddit.getSubredditById(subredditId);
- context.ui.navigateTo(subreddit);
- },
- });
-
- // Navigate to post
- Devvit.addMenuItem({
- label: 'Navigate to post',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const postId = 't3_tzxev3';
- const post = await context.reddit.getPostById(postId);
- context.ui.navigateTo(post);
- },
- });
-
- // Navigate to comment
- Devvit.addMenuItem({
- label: 'Navigate to comment',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const commentId = 't1_i426ob1';
- const comment = await context.reddit.getCommentById(commentId);
- context.ui.navigateTo(comment);
- },
- });
-
- // Interactive post with navigation
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'Navigation Post',
- render: (context) => {
- return (
-
-
-
- );
- },
- });
-
- // Menu action to create interactive post
- Devvit.addMenuItem({
- label: 'Add navigation post',
- location: 'subreddit',
- onPress: async (_event, context) => {
- const subreddit = await context.reddit.getCurrentSubreddit();
- await context.reddit.submitPost({
- title: 'Navigate to post',
- subredditName: subreddit.name,
- preview: (
-
- Loading ...
-
- ),
- });
- context.ui.showToast('Created post!');
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
- ### Parameters
-
- **`context.ui.navigateTo(target)`**
-
- - `target`: Either a URL string or a Reddit object (Subreddit, Post, Comment)
-
-
-
+```ts title="client/index.ts"
+import { navigateTo } from '@devvit/web/client';
+
+// Navigate to external URLs
+navigateTo('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
+
+// Navigate to Reddit URLs
+navigateTo('https://www.reddit.com/r/movies/comments/tzxev3/');
+
+// Navigate to Reddit objects
+async function goToPost() {
+ const post = await fetch('/api/getPost').then(r => r.json());
+ navigateTo(post);
+}
+
+// Use in button handlers or user interactions
+function handleNavigateClick() {
+ navigateTo('https://www.reddit.com/r/webdev');
+}
+```
+
+### Parameters
+
+**`navigateTo(target)`**
+
+- `target`: Either a URL string or a Reddit object (Subreddit, Post, Comment)
:::tip Menu response navigation
For navigation in menu response workflows (when you need server processing before navigation), see the [Menu Actions](./menu-actions.mdx) documentation.
diff --git a/versioned_docs/version-0.12/capabilities/client/overview.mdx b/versioned_docs/version-0.12/capabilities/client/overview.mdx
index 72746638..5d645d5d 100644
--- a/versioned_docs/version-0.12/capabilities/client/overview.mdx
+++ b/versioned_docs/version-0.12/capabilities/client/overview.mdx
@@ -1,91 +1,35 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Client Overview
Client-side effects enable your Devvit app to provide interactive feedback and navigation to users. These effects include showing toasts, displaying forms, navigating to different pages, and more.
-
-
-
- Import client functions from `@devvit/web/client`:
-
- ```ts title="client/index.ts"
- import { showToast, showForm, navigateTo } from '@devvit/web/client';
-
- // Show a toast notification
- showToast('Hello from Devvit Web!');
-
- // Navigate to a URL
- navigateTo('https://www.reddit.com/r/webdev');
-
- // Show a form and handle response
- const result = await showForm({
- form: {
- fields: [
- {
- type: 'string',
- name: 'username',
- label: 'Username'
- }
- ]
- }
- });
-
- if (result) {
- console.log('Form submitted:', result.username);
+Import client functions from `@devvit/web/client`:
+
+```ts title="client/index.ts"
+import { showToast, showForm, navigateTo } from '@devvit/web/client';
+
+// Show a toast notification
+showToast('Hello from Devvit Web!');
+
+// Navigate to a URL
+navigateTo('https://www.reddit.com/r/webdev');
+
+// Show a form and handle response
+const result = await showForm({
+ form: {
+ fields: [
+ {
+ type: 'string',
+ name: 'username',
+ label: 'Username'
+ }
+ ]
}
- ```
-
-
-
-
- Use context methods in event handlers and component render functions:
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- // In a custom post component
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'Interactive Post',
- render: (context) => {
- return (
-
-
-
-
- );
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
-
-
+});
+
+if (result) {
+ console.log('Form submitted:', result.username);
+}
+```
## Available client effects
diff --git a/versioned_docs/version-0.12/capabilities/client/toasts.mdx b/versioned_docs/version-0.12/capabilities/client/toasts.mdx
index 6d94f099..a0ed6194 100644
--- a/versioned_docs/version-0.12/capabilities/client/toasts.mdx
+++ b/versioned_docs/version-0.12/capabilities/client/toasts.mdx
@@ -1,6 +1,3 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Toasts
Display temporary notification messages to users at the bottom of the screen.
@@ -24,108 +21,44 @@ Toasts will not work from scheduled jobs or triggers.
## Basic toast usage
-
-
- ```ts
- import { showToast } from '@devvit/web/client';
-
- // Simple text toast
- showToast('Operation completed successfully!');
-
- // Toast with custom appearance
- showToast({
- text: 'Data saved successfully!',
- appearance: 'success', // 'neutral' | 'success'
- });
-
- // Use in button handlers or user interactions
- function handleButtonClick() {
- try {
- // Perform some operation
- processUserData();
-
- showToast({
- text: 'Your data has been processed!',
- appearance: 'success'
- });
- } catch (error) {
- showToast('Something went wrong. Please try again.');
- }
+```ts
+import { showToast } from '@devvit/web/client';
+
+// Simple text toast
+showToast('Operation completed successfully!');
+
+// Toast with custom appearance
+showToast({
+ text: 'Data saved successfully!',
+ appearance: 'success', // 'neutral' | 'success'
+});
+
+// Use in button handlers or user interactions
+function handleButtonClick() {
+ try {
+ // Perform some operation
+ processUserData();
+
+ showToast({
+ text: 'Your data has been processed!',
+ appearance: 'success'
+ });
+ } catch (error) {
+ showToast('Something went wrong. Please try again.');
}
- ```
-
- ### Parameters
-
- **`showToast(textOrToast)`**
-
- - `textOrToast`: Either a string message or a `Toast` object
-
- **Toast Object Properties:**
-
- - `text` (string): The message to display
- - `appearance` (string, optional): The visual style (`'neutral'` | `'success'`). Defaults to `'neutral'`
-
-
-
- ```ts
- import { Devvit } from '@devvit/public-api';
-
- // Example with menu action
- Devvit.addMenuItem({
- label: 'Save Data',
- location: 'post',
- forUserType: 'moderator',
- onPress: async (event, context) => {
- try {
- // Perform some operation
- await performAction();
-
- // Show success toast
- context.ui.showToast({
- text: 'Data saved successfully!',
- appearance: 'success'
- });
- } catch (error) {
- // Show error toast
- context.ui.showToast('Something went wrong. Please try again.');
- }
- },
- });
-
- // Example in blocks
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'My Custom Post',
- render: (context) => {
- return (
-
-
-
- );
- },
- });
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
- ### Parameters
-
- **`context.ui.showToast(textOrToast)`**
-
- - `textOrToast`: Either a string message or a `Toast` object
-
- **Toast Object Properties:**
-
- - `text` (string): The message to display
- - `appearance` (string, optional): The visual style (`'neutral'` | `'success'`). Defaults to `'neutral'`
-
-
-
+}
+```
+
+### Parameters
+
+**`showToast(textOrToast)`**
+
+- `textOrToast`: Either a string message or a `Toast` object
+
+**Toast Object Properties:**
+
+- `text` (string): The message to display
+- `appearance` (string, optional): The visual style (`'neutral'` | `'success'`). Defaults to `'neutral'`
:::tip Menu response toasts
For toasts in menu response workflows (when you need server processing before showing toasts), see the [Menu Actions](./menu-actions.mdx) documentation.
diff --git a/versioned_docs/version-0.12/capabilities/server/cache-helper.mdx b/versioned_docs/version-0.12/capabilities/server/cache-helper.mdx
index c7724bfe..a6e4e5ce 100644
--- a/versioned_docs/version-0.12/capabilities/server/cache-helper.mdx
+++ b/versioned_docs/version-0.12/capabilities/server/cache-helper.mdx
@@ -14,56 +14,26 @@ Under the covers, it's Redis plus a local in-memory write-through cache. This pr
## Usage
-
-
- You can import cache helper from `@devvit/web/server` in your server source files. The cache helper is not available client-side, so you will see an error if you try to import it in client source files.
+You can import cache helper from `@devvit/web/server` in your server source files. The cache helper is not available client-side, so you will see an error if you try to import it in client source files.
- ```tsx
- import { cache } from '@devvit/web/server';
- ```
-
-
- You need to enable [Redis](../server/redis.mdx) in order to use Cache helper.
-
- ```tsx
- Devvit.configure({
- redis: true,
- // other capabilities
- });
- ```
-
-
+```tsx
+import { cache } from '@devvit/web/server';
+```
## Parameters
-The cache takes a key and a TTL regardless of whether you are using Devvit Web or Devvit Blocks. The only difference is that **the TTL is in seconds for Devvit Web** and **milliseconds for Devvit Blocks / Mod Tools**.
-
-
-
+The cache takes a key and a TTL:
| **Parameters** | **Description** |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `key` | This is a string that identifies a cached response. Instead of making a real request, the app gets the cached response with the key you provide. Make sure to use different keys for different data. For example, if you’re saving post-specific data, add the postId to the cache key, like this: `post_data_${postId})`. |
| `ttl` | Time to live is the number of **seconds** the cached response is expected to be relevant. Once the cached response expires, it will be voided and a real request is made to populate the cache again. You can treat it as a threshold, where ttl of 30 would mean that a request is done no more than once per 30 seconds. |
-
-
-
-| **Parameters** | **Description** |
-| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `key` | This is a string that identifies a cached response. Instead of making a real request, the app gets the cached response with the key you provide. Make sure to use different keys for different data. For example, if you’re saving post-specific data, add the postId to the cache key, like this: `post_data_${postId})`. |
-| `ttl` | Time to live is the number of **milliseconds** the cached response is expected to be relevant. Once the cached response expires, it will be voided and a real request is made to populate the cache again. You can treat it as a threshold, where ttl of 30000 would mean that a request is done no more than once per 30 seconds. |
-
-
-
-
## Example
Here’s a way to set up in-app caching instead of using scheduler or interval to fetch.
-
-
-
-
-
-
- ```tsx
- import { Devvit, useState } from '@devvit/public-api';
-
- Devvit.configure({
- redis: true,
- http: true, // to use `fetch()`
- // other capabilities
- });
-
- // addCustomPostType() is deprecated and will be unsupported. It will not work after June 30. View the announcement below this example.
- Devvit.addCustomPostType({
- name: 'Name',
- render: (context) => {
- const [data, setData] = useState({});
-
- async function getData() {
- const result = await context.cache(
- async () => {
- const response = await fetch('https://example.com');
- if (!response.ok) {
- throw Error(`HTTP error ${response.status}: ${response.statusText}`);
- }
- return await response.json();
- },
- {
- key: context.userId!,
- ttl: 10_000, // millis
- }
- );
-
- setData(result);
- }
-
- return (
-
-
-
- {data.something}
-
- );
- },
- });
-
- export default Devvit;
- ```
- [View `addCustomPostType` deprecation announcement.](https://www.reddit.com/r/Devvit/comments/1r3xcm2/devvit_web_and_the_future_of_devvit/)
-
-
diff --git a/versioned_docs/version-0.12/capabilities/server/http-fetch.mdx b/versioned_docs/version-0.12/capabilities/server/http-fetch.mdx
index 3ea13c22..a3c024c3 100644
--- a/versioned_docs/version-0.12/capabilities/server/http-fetch.mdx
+++ b/versioned_docs/version-0.12/capabilities/server/http-fetch.mdx
@@ -1,6 +1,3 @@
-import Tabs from "@theme/Tabs";
-import TabItem from "@theme/TabItem";
-
# HTTP Fetch
Make requests to allow-listed external domains.
@@ -9,33 +6,17 @@ Your Devvit app can make network requests to access allow-listed external domain
## Enabling HTTP fetch calls
-
-
- ```json title="devvit.json"
- {
- ...
- "permissions": {
- "http": {
- "enable": true,
- "domains": ["my-site.com", "another-domain.net"]
- }
+```json title="devvit.json"
+{
+ ...
+ "permissions": {
+ "http": {
+ "enable": true,
+ "domains": ["my-site.com", "another-domain.net"]
}
}
- ```
-
-
- ```ts
- import { Devvit } from '@devvit/public-api';
-
-Devvit.configure({
-http: {
-domains: ['my-site.com', 'another-domain.net'],
-},
-});
-
-````
-
-
+}
+```
### Requesting a domain to be allow-listed
@@ -64,25 +45,22 @@ Apps must request each individual domain that it intends to fetch, even if the d
## Example usage
-
-
-
- Devvit Web applications have two different contexts for using fetch:
+Devvit Web applications have two different contexts for using fetch:
- ### Server-side fetch
+### Server-side fetch
- Server-side fetch allows your app to make HTTP requests to allowlisted external domains from your server-side code (e.g., API routes, server actions):
+Server-side fetch allows your app to make HTTP requests to allowlisted external domains from your server-side code (e.g., API routes, server actions):
```tsx title="server/index.ts"
- const response = await fetch('https://example.com/api/data', {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
- });
+const response = await fetch('https://example.com/api/data', {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+});
- const data = await response.json();
- console.log('External API response:', data);
+const data = await response.json();
+console.log('External API response:', data);
````
### Client-side fetch
@@ -98,7 +76,7 @@ Client-side fetch has different restrictions and can only make requests to your
```tsx title="client/index.ts"
const handleFetchData = async () => {
- // ✅ Correct: Fetching your own webview's API endpoint
+ // Correct: fetching your own webview's API endpoint
const response = await fetch("/api/user-data", {
method: "GET",
headers: {
@@ -110,51 +88,13 @@ const handleFetchData = async () => {
console.log("API response:", data);
};
-// ❌ Incorrect: Cannot fetch external domains from client-side
+// Incorrect: cannot fetch external domains from client-side
// const response = await fetch('https://external-api.com/data');
-// ❌ Incorrect: Endpoint must end with /api
+// Incorrect: endpoint must end with /api
// const response = await fetch('/user-data');
```
-
-
-
- For Devvit Blocks and Mod Tools, fetch is available within menu actions, triggers, and other server-side contexts:
-
- ```ts
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- http: {
- domains: ['example.com'],
- },
- });
-
- Devvit.addMenuItem({
- location: 'comment',
- label: 'Sample HTTP request',
- onPress: async (_event, context) => {
- console.log(`Comment ID: ${context.commentId}`);
- const response = await fetch('https://example.com', {
- method: 'post',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ content: context.commentId }),
- });
- context.ui.showToast(
- `Invoked HTTP request on comment: ${context.commentId}. Completed with status: ${response.status}`
- );
- },
- });
-
- export default Devvit;
- ```
-
-
-
-
## Troubleshooting
If you see the following error, it means HTTP Fetch requests are hitting the internal timeout limits. To resolve this:
diff --git a/versioned_docs/version-0.12/capabilities/server/media-uploads.mdx b/versioned_docs/version-0.12/capabilities/server/media-uploads.mdx
index 7316f1a7..b9e61a94 100644
--- a/versioned_docs/version-0.12/capabilities/server/media-uploads.mdx
+++ b/versioned_docs/version-0.12/capabilities/server/media-uploads.mdx
@@ -1,6 +1,3 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Media Uploads
:::warning
@@ -24,29 +21,16 @@ Enable the `media` permission in your `devvit.json` file.
## Using media uploads
On the server, you can pass the URL of any remotely hosted image (even if its not hosted on Reddit) to the `media.upload` function. This function will return a Reddit URL. Both HTTP and data URLs are supported.
-
-
- ```ts title="server/index.ts"
- import { media } from '@devvit/media';
- function submitImage() {
- const response = await media.upload({
- url: 'https://media2.giphy.com/media/xTiN0CNHgoRf1Ha7CM/giphy.gif',
- type: 'gif',
- });
- }
- ```
-
-
- ```ts
- import { Devvit } from '@devvit/public-api';
+```ts title="server/index.ts"
+import { media } from '@devvit/media';
+function submitImage() {
const response = await media.upload({
url: 'https://media2.giphy.com/media/xTiN0CNHgoRf1Ha7CM/giphy.gif',
type: 'gif',
});
- ```
-
-
+}
+```
## Canvas screenshots
diff --git a/versioned_docs/version-0.12/capabilities/server/reddit-api.mdx b/versioned_docs/version-0.12/capabilities/server/reddit-api.mdx
index cb9191ff..a2b32781 100644
--- a/versioned_docs/version-0.12/capabilities/server/reddit-api.mdx
+++ b/versioned_docs/version-0.12/capabilities/server/reddit-api.mdx
@@ -1,6 +1,3 @@
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-
# Reddit API Overview
The Reddit API allows you to read and write Reddit content such as posts / comments / upvotes, in order to integrate your app's behavior with the content of the community it's installed in.
@@ -24,32 +21,17 @@ Devvit apps cannot access certain private user data. This data is private to the
Here's how to obtain a reference to the Reddit client
-
-
- ```json title="devvit.json"
- {
- "permissions": {
- "reddit": true
- }
+```json title="devvit.json"
+{
+ "permissions": {
+ "reddit": true
}
- ```
- ```ts title="server/index.ts"
- import { reddit } from '@devvit/reddit';
- ```
-
-
- ```ts title="devvit.tsx"
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- redditAPI: true,
- });
+}
+```
- //Then, in any function that has a reference to Devvit.Context:
- const reddit = context.reddit;
- ```
-
-
+```ts title="server/index.ts"
+import { reddit } from '@devvit/reddit';
+```
## Reddit Thing IDs
@@ -79,9 +61,7 @@ const parentId = comment.parentId; // 't3_abc123' or 't1_def456'
## Example usage
### Submitting a post
-
-
- ```ts
+```ts
import { Devvit } from '@devvit/public-api';
import { context, reddit } from '@devvit/web/server';
@@ -100,36 +80,7 @@ export const createPost = async () => {
entry: 'default',
});
};
- ```
-
-
-
-```tsx
-import { Devvit } from '@devvit/public-api';
-
-Devvit.configure({
- redditAPI: true,
-});
-
-function createPost(context: Devvit.Context) {
- const currentSubreddit = context.reddit.getCurrentSubreddit();
- if (!currentSubreddit) {
- throw new Error('No subreddit found');
- }
-
- return context.reddit.submitPost({
- title: 'My custom post',
- subredditName: currentSubreddit.name,
- preview: (
-
- Loading...
-
- ),
- });
-}
```
-
-
### Submitting a comment
@@ -138,42 +89,19 @@ Auto-comments should be used to spark conversation in the post comments, but you
:::
-
-
- ```ts
- import { context, reddit } from '@devvit/web/server';
+```ts
+import { context, reddit } from '@devvit/web/server';
- export const createComment = async () => {
- const { subredditName } = context;
- if (!subredditName) {
- throw new Error('subredditName is required');
- }
+export const createComment = async () => {
+ const { subredditName } = context;
+ if (!subredditName) {
+ throw new Error('subredditName is required');
+ }
- reddit.submitComment({
- postId: 't3_123456', // Replace with the actual post ID
- text: 'This is a comment from a Devvit app',
- runAs: 'USER' // Optional: specify the user to run as
- });
- };
-```
-
-
- ```tsx
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- redditAPI: true,
- });
-
- function createComment(context: Devvit.Context) {
- const { reddit } = context;
-
- reddit.submitComment({
- postId: 't3_123456', // Replace with the actual post ID
- text: 'This is a comment from a Devvit app',
- runAs: RunAs.USER, // Optional: specify the user to run as
- });
- };
+ reddit.submitComment({
+ postId: 't3_123456', // Replace with the actual post ID
+ text: 'This is a comment from a Devvit app',
+ runAs: 'USER' // Optional: specify the user to run as
+ });
+};
```
-
-
diff --git a/versioned_docs/version-0.12/capabilities/server/redis.mdx b/versioned_docs/version-0.12/capabilities/server/redis.mdx
index bcca403a..61a62107 100644
--- a/versioned_docs/version-0.12/capabilities/server/redis.mdx
+++ b/versioned_docs/version-0.12/capabilities/server/redis.mdx
@@ -30,9 +30,7 @@ All limits are applied at a per-installation granularity.
### Menu actions
-
-
- ```js title="devvit.json"
+```js title="devvit.json"
{
"menuActions": [
{
@@ -89,22 +87,6 @@ All limits are applied at a per-installation granularity.
-
-
- ```ts
- Devvit.addMenuItem({
- location: 'subreddit',
- label: 'Test Redis',
- onPress: async (event, { redis }) => {
- const key = 'hello';
- await redis.set(key, 'world');
- const value = await redis.get(key);
- console.log(`${key}: ${value}`);
- },
- });
- ```
-
-
### Games
@@ -117,11 +99,9 @@ You can take a look at this [Game Template](https://github.com/reddit/devvit-tem
Not all Redis features are supported. If you would like to request a specific Redis feature, please reach out to our team [via modmail](https://www.reddit.com/message/compose/?to=%2Fr%2FDevvit) or Discord.
:::
-For all examples below, we assume that you already have obtained a Redis Client. Here's how to obtain a Redis Client for Devvit Web, Devvit Blocks and Mod Tools:
+For all examples below, we assume that you already have obtained a Redis Client. Here's how to obtain a Redis Client:
-
-
- ```json title="devvit.json"
+```json title="devvit.json"
{
"permissions": {
"redis": true
@@ -131,20 +111,6 @@ For all examples below, we assume that you already have obtained a Redis Client.
```ts title="server/index.ts"
import { redis } from '@devvit/redis';
```
-
-
- ```ts title="devvit.tsx"
- import { Devvit } from '@devvit/public-api';
-
- Devvit.configure({
- redis: true,
- });
-
- //Then, in any function that has a reference to Devvit.Context:
- const redis = context.redis;
- ```
-
-
### Simple read/write
diff --git a/versioned_docs/version-0.12/capabilities/server/triggers.mdx b/versioned_docs/version-0.12/capabilities/server/triggers.mdx
index f9be593c..409a6d18 100644
--- a/versioned_docs/version-0.12/capabilities/server/triggers.mdx
+++ b/versioned_docs/version-0.12/capabilities/server/triggers.mdx
@@ -39,9 +39,7 @@ A full list of events and their payloads can be found in the [EventTypes documen
### 1. Add triggers and endpoints to `devvit.json`
-
-
- Declare the triggers and their corresponding endpoints in your `devvit.json`:
+Declare the triggers and their corresponding endpoints in your `devvit.json`:
```json
"triggers": {
@@ -51,28 +49,10 @@ A full list of events and their payloads can be found in the [EventTypes documen
}
```
-
-
- Declare the triggers in your `devvit.json`:
-
-```json
-{
- "name": "your-app-name",
- "blocks": {
- "entry": "src/main.tsx",
- "triggers": ["onPostCreate"]
- }
-}
-```
-
-
-
### 2. Handle trigger events in your server logic
-
-
- Listen for the events in your server and access the data passed into the request:
+Listen for the events in your server and access the data passed into the request:
(
-
-
- Handle trigger events in your main file. Example (`src/main.tsx`):
-
-```tsx
-import { Devvit } from "@devvit/public-api";
-
-// Handling a PostSubmit event
-Devvit.addTrigger({
- event: "PostSubmit", // Event name from above
- onEvent: async (event) => {
- console.log(`Received OnPostSubmit event:\n${JSON.stringify(event)}`);
- },
-});
-
-// Handling multiple events: PostUpdate and PostReport
-Devvit.addTrigger({
- events: ["PostUpdate", "PostReport"], // An array of events
- onEvent: async (event) => {
- if (event.type == "PostUpdate") {
- console.log(`Received OnPostUpdate event:\n${JSON.stringify(request)}`);
- } else if (event.type === "PostReport") {
- console.log(`Received OnPostReport event:\n${JSON.stringify(request)}`);
- }
- },
-});
-
-export default Devvit;
-```
-
-
-
-
## Best practices
- Avoid creating recursive triggers that could cause infinite loops or crashes (for example, a comment trigger that creates a comment).