diff --git a/fern/products/docs/pages/changelog/2025-11-25.mdx b/fern/products/docs/pages/changelog/2025-11-25.mdx new file mode 100644 index 000000000..e0f2e696b --- /dev/null +++ b/fern/products/docs/pages/changelog/2025-11-25.mdx @@ -0,0 +1,10 @@ +## Custom React components: file imports and API calls + +The [custom React components](/learn/docs/writing-content/custom-react-components) documentation now includes guidance on importing files, using assets, and making API calls from your components. + +New sections cover: + +- **Importing CSS files** - Create separate stylesheets and import them into your components +- **Importing other modules** - Split component logic across multiple files +- **Using SVG and image assets** - Reference images and SVG files in your components +- **Making API calls** - Fetch data from APIs with security best practices for handling API keys diff --git a/fern/products/docs/pages/component-library/custom-components/custom-react-components.mdx b/fern/products/docs/pages/component-library/custom-components/custom-react-components.mdx index 2bc5dabb8..fcae7cc12 100644 --- a/fern/products/docs/pages/component-library/custom-components/custom-react-components.mdx +++ b/fern/products/docs/pages/component-library/custom-components/custom-react-components.mdx @@ -59,6 +59,170 @@ import { CustomCard } from "../components/CustomCard" ``` +## Importing files and assets + +Custom React components can import other files from your `fern/` folder, including CSS files, JavaScript/TypeScript modules, and assets like SVGs and images. + +### Importing CSS files + +You can create separate CSS files and import them directly into your components: + +```css components/PlantCard.css +.plant-card { + padding: 1rem; + border-radius: 8px; + border: 1px solid #e0e0e0; +} + +.plant-card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} + +.plant-card-title { + font-size: 1.25rem; + font-weight: 600; + margin-bottom: 0.5rem; +} +``` + +```tsx components/PlantCard.tsx +import "./PlantCard.css"; + +export const PlantCard = ({ name, species }) => { + return ( +
+

{name}

+

{species}

+
+ ); +}; +``` + +### Importing other modules + +You can split your component logic across multiple files and import them as needed: + +```ts components/utils/plantHelpers.ts +export const formatPlantName = (name: string) => { + return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase(); +}; + +export const getWateringSchedule = (plantType: string) => { + const schedules = { + succulent: "Every 2 weeks", + fern: "Every 2-3 days", + cactus: "Every 3 weeks", + }; + return schedules[plantType] || "Weekly"; +}; +``` + +```tsx components/PlantInfo.tsx +import { formatPlantName, getWateringSchedule } from "./utils/plantHelpers"; + +export const PlantInfo = ({ name, type }) => { + return ( +
+

{formatPlantName(name)}

+

Watering: {getWateringSchedule(type)}

+
+ ); +}; +``` + +### Using SVG and image assets + +You can import SVG files directly as React components or reference image assets: + +```tsx components/PlantIcon.tsx +import LeafIcon from "./assets/leaf-icon.svg"; + +export const PlantIcon = ({ size = 24 }) => { + return Plant; +}; +``` + +For images stored in your `fern/` folder, reference them using paths relative to the component file or relative to the `fern/` folder root: + +```tsx components/PlantGallery.tsx +export const PlantGallery = () => { + return ( +
+ {/* Relative to component file */} + Monstera + + {/* Relative to fern folder root */} + Fiddle Leaf Fig +
+ ); +}; +``` + + +Make sure to include any directories containing your CSS, utility files, or assets in the `mdx-components` configuration in `docs.yml`: + +```yaml docs.yml +experimental: + mdx-components: + - ./components + - ./components/utils + - ./components/assets +``` + + +## Making API calls + +Custom React components can make client-side API calls using `fetch` or other HTTP libraries. Since these components run in the browser, any API calls happen on the client side. + +```tsx components/PlantSearch.tsx +import { useState } from "react"; + +export const PlantSearch = ({ apiEndpoint }) => { + const [plants, setPlants] = useState([]); + const [loading, setLoading] = useState(false); + + const searchPlants = async (query: string) => { + setLoading(true); + try { + const response = await fetch(`${apiEndpoint}/plants?search=${query}`); + const data = await response.json(); + setPlants(data.plants); + } catch (error) { + console.error("Failed to fetch plants:", error); + } finally { + setLoading(false); + } + }; + + return ( +
+ searchPlants(e.target.value)} + /> + {loading ?

Loading...

: ( + + )} +
+ ); +}; +``` + + +Never include secret API keys directly in your component code. Since custom React components run in the browser, any API keys embedded in the code are visible to users. + +For API calls that require authentication, consider these approaches: + +- **Use public API keys**: Some APIs provide publishable keys that are safe to expose in client-side code. +- **Pass keys as props**: Pass API keys as props from your MDX file, where you can use environment variables or other secure methods. +- **Use a backend proxy**: Route API calls through your own backend server that securely stores the API key. + + ## Why not just use custom CSS and JS instead? While you can bundle React components as custom JavaScript, using Fern's built-in React component support provides several key advantages: