Assets and Files
There are two ways to add an asset to your Redwood app:
- co-locate it with the component using it and import it into the component as if it were code
- add it to the
web/public
directory and reference it relative to your site's root
Where possible, prefer the first strategy.
It lets Vite include the asset in the bundle when the file is small enough.
Co-locating and Importing Assets
Let's say you want to show your app's logo in your Header
component.
First, add your logo to the Header
component's directory:
web/src/components/Header/
├── logo.png
├── Header.js
├── Header.stories.js
└── Header.test.js
Then, in the Header
component, import your logo as if it were code:
import logo from './logo.png'
const Header = () => {
return (
<header>
{/* ... */}
<img src={logo} alt="Logo" />
</header>
)
}
export default Header
If you're curious how this works, see the Vite docs on static asset handling.
Adding to the web/public
Directory
You can also add assets to the web/public
directory, effectively adding static files to your app.
During dev and build, Redwood copies web/public
's contents into web/dist
.
Changes to
web/public
don't hot-reload.
Again, because assets in this directory don't go through Vite, use this strategy sparingly, and mainly for assets like favicons, manifests, robots.txt
, libraries incompatible with Vite, etc.
Example: Adding Your Logo and Favicon to web/public
Let's say that you've added your logo and favicon to web/public
:
web/public/
├── img/
│ └── logo.png
└── favicon.png
When you run yarn rw dev
and yarn rw build
, Redwood copies
web/public/img/logo.png
to web/dist/img/logo.png
and web/public/favicon.png
to web/dist/favicon.png
:
web/dist/
├── static/
│ ├── js/
│ └── css/
├── img/
│ └── logo.png
└── favicon.png
You can reference these files in your code without any special handling:
import { Head } from '@redwoodjs/web'
const Header = () => {
return (
<>
<Head>
<link rel="icon" type="image/png" href="favicon.png" />
</Head>
<img src="img/logo.png" alt="Logo" />
</>
)
}
export default Header
Styling SVGs: The special type of image
By default you can import and use SVG images like any other image asset.
import svgIconSrc from '../mySvg.svg'
const Example = () => {
return (
<>
<img src={svgIconSrc} alt="Logo" />
</>
)
}
export default Example
Sometimes however, you might want more control over styling your SVGs - maybe you want to modify the stroke-width
or fill
color.
The easiest way to achieve this, is to make your SVGs a React component. Open up your SVG file, and drop in its contents into a component – for example:
import type { SVGProps } from "react"
export const CarIcon = (props: SVGProps) => {
return (
// 👇 content of your SVG file
<svg
className="fill-blue-500" // 👈 you can use classes, like with tailwind
stroke={props.strokeColor} // or adjust properties directly
// ...
If you needed to convert a whole library of SVGs into stylable (or animatable!) components, one easy way would be to use the SVGR cli
Custom fonts
There are many different ways to peel this potato – it's all a search away – but if you're using the CSS @font-face
rule, we have a quick tip for you:
- Place your fonts in the public folder, so it gets carried across
- In your CSS, use absolute paths - the public folder being your root - to point to the font file (same as the Vite docs), for example:
web/
├── src
├── App.tsx
├── entry.client.tsx
├── index.css
├── ...
├── public
│ ├── favicon.png
│ ├── fonts
│ │ └── RedwoodNeue.woff2
/* in e.g. index.css */
@font-face {
font-family: 'Redwood Neue';
/* 👇 it's a relative path */
src: url('/fonts/RedwoodNeue.woff2')
format('woff2');
font-weight: 300;
font-style: italic;
ascent-override: 97%;
}