Introductory tutorial
Learn how to import and style Joy UI components to build a simple login page with light and dark modes.
This tutorial will walk you through how to assemble the UI for a basic login page using Joy UI.
You'll be introduced to several common components as well as some of the props you can use to control their styles.
You'll also encounter key features of Joy UI such as global variants, the sx
prop, and the useColorScheme
hook.
By the end, you should understand how to:
- import and customize Joy UI components
- add styles to Joy UI components with
sx
- override default HTML elements with
component
- toggle light and dark mode with
useColorScheme
Interactive demo
Here's what the final product looks like—click on the <> icon underneath the demo to see the full source code:
Prerequisites
This tutorial assumes that you've already:
- set up a React app—try Create React App if you need a boilerplate
- installed Joy UI in your app—see Installation for instructions
Import the Sheet component for structure
The Sheet component is a <div>
container that supports Joy UI's global variants feature, helping to ensure consistency across your app.
Import Sheet and add it to your app as shown below.
(If you're using Create React App, for example, all of this code should go in App.js
.)
<span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> CssVarsProvider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@mui/joy/styles'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Sheet <span class="token keyword">from</span> <span class="token string">'@mui/joy/Sheet'</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">CssVarsProvider</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Sheet</span></span> <span class="token attr-name">variant</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>outlined<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Welcome<span class="token operator">!</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Sheet</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">CssVarsProvider</span></span><span class="token punctuation">></span></span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
Add styles with the sx prop
All Joy UI components accept the sx
prop, which gives you access to a shorthand syntax for writing CSS.
It's great for creating one-off customizations or rapidly experimenting with different styles.
Replace your basic Sheet from the previous step with the following sx
-styled Sheet:
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Sheet</span></span>
<span class="token attr-name">sx</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span>
<span class="token literal-property property">width</span><span class="token operator">:</span> <span class="token number">300</span><span class="token punctuation">,</span>
<span class="token literal-property property">mx</span><span class="token operator">:</span> <span class="token string">'auto'</span><span class="token punctuation">,</span> <span class="token comment">// margin left & right</span>
<span class="token literal-property property">my</span><span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token comment">// margin top & bottom</span>
<span class="token literal-property property">py</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token comment">// padding top & bottom</span>
<span class="token literal-property property">px</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token comment">// padding left & right</span>
<span class="token literal-property property">display</span><span class="token operator">:</span> <span class="token string">'flex'</span><span class="token punctuation">,</span>
<span class="token literal-property property">flexDirection</span><span class="token operator">:</span> <span class="token string">'column'</span><span class="token punctuation">,</span>
<span class="token literal-property property">gap</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
<span class="token literal-property property">borderRadius</span><span class="token operator">:</span> <span class="token string">'sm'</span><span class="token punctuation">,</span>
<span class="token literal-property property">boxShadow</span><span class="token operator">:</span> <span class="token string">'md'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">}</span></span>
<span class="token punctuation">></span></span>
Welcome<span class="token operator">!</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Sheet</span></span><span class="token punctuation">></span></span>
Add text with the Typography component
The Typography component replaces HTML header, paragraph, and span tags to help maintain a consistent hierarchy of text on the page.
Add an import for Typography with the rest of your imports:
<span class="token keyword">import</span> Typography <span class="token keyword">from</span> <span class="token string">'@mui/joy/Typography'</span><span class="token punctuation">;</span>
Replace Welcome!
inside your Sheet component with this <div>
:
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Typography</span></span> <span class="token attr-name">level</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h4<span class="token punctuation">"</span></span> <span class="token attr-name">component</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>h1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
Welcome<span class="token operator">!</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Typography</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Typography</span></span> <span class="token attr-name">level</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>body2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Sign <span class="token keyword">in</span> to <span class="token keyword">continue</span><span class="token punctuation">.</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Typography</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
Add text field for user inputs
The Form Control, Form Label, and Input components can be used together to provide you with a sophisticated field for user input.
Add imports for Form Control, Form Label, and Input with the rest of your imports:
<span class="token keyword">import</span> FormControl <span class="token keyword">from</span> <span class="token string">'@mui/joy/FormControl'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> FormLabel <span class="token keyword">from</span> <span class="token string">'@mui/joy/FormLabel'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Input <span class="token keyword">from</span> <span class="token string">'@mui/joy/Input'</span><span class="token punctuation">;</span>
Insert these two text fields below the <div>
from the previous step, inside the Sheet:
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">FormControl</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">FormLabel</span></span><span class="token punctuation">></span></span>Email<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">FormLabel</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Input</span></span>
<span class="token comment">// html input attribute</span>
<span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span>
<span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span>
<span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>johndoe@email.com<span class="token punctuation">"</span></span>
<span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">FormControl</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">FormControl</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">FormLabel</span></span><span class="token punctuation">></span></span>Password<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">FormLabel</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Input</span></span>
<span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span>
<span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span>
<span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span>
<span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">FormControl</span></span><span class="token punctuation">></span></span>
Import Button and Link for user actions
The Button and Link components replace the HTML <button>
and <a>
tags, respectively, giving you access to global variants, the sx
and component
props, and more.
Add the following imports with the rest in your app:
<span class="token keyword">import</span> Button <span class="token keyword">from</span> <span class="token string">'@mui/joy/Button'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Link <span class="token keyword">from</span> <span class="token string">'@mui/joy/Link'</span><span class="token punctuation">;</span>
Add the following Button, Typography, and Link components after the text fields from the previous step, still nested inside the Sheet.
Notice that the Link is appended to the Typography inside of the endDecorator
prop:
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Button</span></span> <span class="token attr-name">sx</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">mt</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token comment">/* margin top */</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span>
Log <span class="token keyword">in</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Button</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Typography</span></span>
<span class="token attr-name">endDecorator</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Link</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/sign-up<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Sign up<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Link</span></span><span class="token punctuation">></span></span><span class="token punctuation">}</span></span>
<span class="token attr-name">fontSize</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sm<span class="token punctuation">"</span></span>
<span class="token attr-name">sx</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token literal-property property">alignSelf</span><span class="token operator">:</span> <span class="token string">'center'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span>
<span class="token punctuation">></span></span>
Don't have an account<span class="token operator">?</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Typography</span></span><span class="token punctuation">></span></span>
🎁 Bonus: Build a toggle for light and dark mode
The useColorScheme
hook aids in the implementation of a toggle button for switching between light and dark mode in an app.
It also enables Joy UI to ensure that the user-selected mode (which is stored in localStorage
by default) stays in sync across browser tabs.
Add useColorScheme
to your import from @mui/joy/styles
:
<span class="token keyword">import</span> <span class="token punctuation">{</span> CssVarsProvider<span class="token punctuation">,</span> useColorScheme <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@mui/joy/styles'</span><span class="token punctuation">;</span>
Next, create a light/dark mode toggle button by adding the following code snippet in between your imports and your App()
:
<span class="token keyword">function</span> <span class="token function">ModeToggle</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> mode<span class="token punctuation">,</span> setMode <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useColorScheme</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token punctuation">[</span>mounted<span class="token punctuation">,</span> setMounted<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// necessary for server-side rendering</span>
<span class="token comment">// because mode is undefined on the server</span>
React<span class="token punctuation">.</span><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token function">setMounted</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mounted<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Button</span></span>
<span class="token attr-name">variant</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>outlined<span class="token punctuation">"</span></span>
<span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token function">setMode</span><span class="token punctuation">(</span>mode <span class="token operator">===</span> <span class="token string">'light'</span> <span class="token operator">?</span> <span class="token string">'dark'</span> <span class="token operator">:</span> <span class="token string">'light'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">}</span></span>
<span class="token punctuation">></span></span>
<span class="token punctuation">{</span>mode <span class="token operator">===</span> <span class="token string">'light'</span> <span class="token operator">?</span> <span class="token string">'Turn dark'</span> <span class="token operator">:</span> <span class="token string">'Turn light'</span><span class="token punctuation">}</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Button</span></span><span class="token punctuation">></span></span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
Finally, add your newly built <ModeToggle />
button above <Sheet />
:
<span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line">export default function App() {
</span><span class="token prefix unchanged"> </span><span class="token line"> return (
</span><span class="token prefix unchanged"> </span><span class="token line"> <CssVarsProvider>
</span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line"> <ModeToggle />
</span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> <Sheet>...</Sheet>
</span><span class="token prefix unchanged"> </span><span class="token line"> </CssVarsProvider>
</span><span class="token prefix unchanged"> </span><span class="token line"> );
</span><span class="token prefix unchanged"> </span><span class="token line">}</span></span>
Your app should now look like the interactive demo at the top of the page. Great job making it all the way to the end!
Summary
Here's a recap of the components used:
Here are some of the major features introduced:
Next steps
This tutorial does not cover theming or general component customization. Learn more about different customization approaches and when to apply them.
To see some more sophisticated examples of Joy UI in action, check out our collection of templates.
Are you migrating from Material UI? Learn how to work with Joy UI and Material UI together in one app.