docs: migrate UI docs (#13245)

* docs: create a new UI docs project (#13233)

* docs: create a new UI docs project

* fix installation errors

* docs: migrate UI docs content to new project (#13241)

* Fix content

* added examples for some components

* finish adding examples

* lint fix

* fix build errors

* delete empty files

* path fixes + refactor

* fix build error
This commit is contained in:
Shahed Nasser
2025-08-20 11:42:25 +03:00
committed by GitHub
parent 5b7a041246
commit d1a1135328
748 changed files with 13079 additions and 7319 deletions
+39
View File
@@ -0,0 +1,39 @@
---
generate_toc: true
---
import { Colors } from "@/components/Colors"
export const metadata = {
title: `Medusa UI Colors`,
}
# {metadata.title}
In this guide, you'll learn about the color classes available in Medusa UI and how to use them.
## Overview
Medusa UI provides Tailwind CSS classes for colors from the Medusa design system. These classes can be used to style components and elements consistently across your Medusa and standalone applications.
To view the colors in the list below in dark mode, switch the documentation's theme from the menu in the top right.
To copy a color's Tailwind CSS class from the list below, click on it.
### How to Use the Medusa UI Colors
You can use the color classes in your Medusa Admin customizations or standalone projects that have the `@medusajs/ui` package installed.
You can apply the color classes as CSS classes to any element.
For example, to set the background color of the document's body:
```tsx
<body className="bg-medusa-bg-base">
...
</body>
```
---
<Colors />
+53
View File
@@ -0,0 +1,53 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Alert`,
}
# {metadata.title}
A component for displaying important messages.
In this guide, you'll learn how to use the Alert component.
<ComponentExample name="alert-demo" />
---
## Usage
```tsx
import { Alert } from "@medusajs/ui"
```
```tsx
<Alert>Here's a message</Alert>
```
---
## API Reference
<ComponentReference mainComponent="Alert" />
---
## Examples
### Success Alert
<ComponentExample name="alert-success" />
### Warning Alert
<ComponentExample name="alert-warning" />
### Error Alert
<ComponentExample name="alert-error" />
### Dismissible Alert
<ComponentExample name="alert-dismissable" hideFeedback />
@@ -0,0 +1,59 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Avatar`,
}
# {metadata.title}
A component for displaying user avatars with a fallback option.
In this guide, you'll learn how to use the Avatar component.
<ComponentExample name="avatar-demo" />
## Usage
```tsx
import { Avatar } from "@medusajs/ui"
```
```tsx
<Avatar
src="https://avatars.githubusercontent.com/u/10656202?v=4"
fallback="M"
/>
```
---
## API Reference
<ComponentReference mainComponent="Avatar" />
---
## Examples
### Avatar Variants
<ComponentExample name="avatar-variants" />
### Avatar Sizes
<ComponentExample name="avatar-sizes" />
### Avatar Fallback Only
<ComponentExample name="avatar-fallback" />
### Avatar Custom Styling
<ComponentExample name="avatar-custom-style" />
### Avatar Accessibility
You can add the `aria-label` prop to the Avatar component for better accessibility.
<ComponentExample name="avatar-accessible" hideFeedback />
+46
View File
@@ -0,0 +1,46 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Badge`,
}
# {metadata.title}
A component for displaying labels or indicators in a badge style.
In this guide, you'll learn how to use the Badge component.
<ComponentExample name="badge-demo" />
## Usage
```tsx
import { Badge } from "@medusajs/ui"
```
```tsx
<Badge>Badge</Badge>
```
---
## API Reference
<ComponentReference mainComponent="Badge" />
---
## Examples
### Badge Colors
<ComponentExample name="badge-all-colors" />
### Badge Sizes
<ComponentExample name="badge-all-sizes" />
### Badge Rounded Variants
<ComponentExample name="badge-all-rounded" hideFeedback />
@@ -0,0 +1,56 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Button`,
}
# {metadata.title}
A component for rendering buttons using Medusa's design system.
In this guide, you'll learn how to use the Button component.
<ComponentExample name="button-demo" />
---
## Usage
```tsx
import { Button } from "@medusajs/ui"
```
```tsx
<Button>Button</Button>
```
---
## API Reference
<ComponentReference mainComponent="Button" />
---
## Examples
### Button Variants
<ComponentExample name="button-all-variants" />
### Button Sizes
<ComponentExample name="button-all-sizes" />
### Button Loading State
<ComponentExample name="button-loading" />
### Button with Icon
<ComponentExample name="button-with-icon" />
### Button as Link
<ComponentExample name="button-as-link" hideFeedback />
@@ -0,0 +1,46 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Calendar`,
}
# {metadata.title}
A component for displaying a calendar interface with date selection capability.
In this guide, you'll learn how to use the Calendar component.
<ComponentExample name="calendar-demo" />
## Usage
```tsx
import { Calendar } from "@medusajs/ui"
```
```tsx
<Calendar />
```
---
## API Reference
<ComponentReference mainComponent="Calendar" />
---
## Examples
### Controlled
<ComponentExample name="calendar-controlled" />
### Min/Max Dates
<ComponentExample name="calendar-min-max" />
### Unavailable Dates
<ComponentExample name="calendar-unavailable" hideFeedback />
@@ -0,0 +1,42 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Checkbox`,
}
# {metadata.title}
A component for rendering checkbox inputs using Medusa's design system.
In this guide, you'll learn how to use the Checkbox component.
<ComponentExample name="checkbox-demo" />
## Usage
```tsx
import { Checkbox } from "@medusajs/ui"
```
```tsx
<Checkbox />
```
---
## API Reference
<ComponentReference mainComponent="Checkbox" />
---
## Examples
### Checkbox All States
<ComponentExample name="checkbox-all-states" />
### Controlled Checkbox
<ComponentExample name="checkbox-controlled" hideFeedback />
@@ -0,0 +1,97 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Code Block`,
}
# {metadata.title}
A component for displaying code snippets with syntax highlighting and copy functionality.
In this guide, you'll learn how to use the Code Block component.
<ComponentExample name="code-block-demo" />
## Usage
```tsx
import { CodeBlock } from "@medusajs/ui"
```
```tsx
<CodeBlock
snippets={[
{
language: "tsx",
label: "Label",
code: "import { useProduct } from \"medusa-react\"",
},
]}
>
<CodeBlock.Header />
<CodeBlock.Body />
</CodeBlock>
```
---
## API Reference
<ComponentReference mainComponent="CodeBlock" componentsToShow={[
"CodeBlock",
"CodeBlock.Header",
"CodeBlock.Header.Meta",
"CodeBlock.Body"
]} />
---
## Usage Outside Medusa Admin
If you're using the `CodeBlock` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree, as the `CodeBlock.Header` component uses a [Tooltip](../tooltip/page.mdx#usage-outside-medusa-admin):
```tsx
<TooltipProvider>
<CodeBlock
snippets={[
{
language: "tsx",
label: "Label",
code: "import { useProduct } from \"medusa-react\"",
},
]}
>
<CodeBlock.Header />
<CodeBlock.Body />
</CodeBlock>
</TooltipProvider>
```
---
## Examples
### Single Snippet
If you want to only show a code sample for one language or API, you can choose to hide the snippet labels:
<ComponentExample name="code-block-single" />
### No Header
You can also omit the header entirely:
<ComponentExample name="code-block-no-header" />
### No Line Numbers
<ComponentExample name="code-block-no-lines" />
### No Copy Button
<ComponentExample name="code-block-no-copy" hideFeedback />
@@ -0,0 +1,57 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Command Bar`,
}
# {metadata.title}
A component that displays a command bar with a list of commands to perform on a bulk selection of items.
In this guide, you'll learn how to use the Command Bar component.
<ComponentExample name="command-bar-demo" />
## Usage
```tsx
import { CommandBar } from "@medusajs/ui"
```
```tsx
<CommandBar open={open}>
<CommandBar.Bar>
<CommandBar.Value>{count} selected</CommandBar.Value>
<CommandBar.Seperator />
<CommandBar.Command
action={onDelete}
label="Delete"
shortcut="d"
/>
<CommandBar.Seperator />
<CommandBar.Command
action={onEdit}
label="Edit"
shortcut="e"
/>
</CommandBar.Bar>
</CommandBar>
```
---
## API Reference
<ComponentReference mainComponent="CommandBar" componentsToShow={[
"CommandBar",
"CommandBar.Bar",
"CommandBar.Value",
"CommandBar.Seperator",
"CommandBar.Command"
]} hideFeedback />
@@ -0,0 +1,50 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Command`,
}
# {metadata.title}
A component that renders an unhighlighted code block, useful for one-liners or API routes.
In this guide, you'll learn how to use the Command component.
<ComponentExample name="command-demo" />
## Usage
```tsx
import { Command } from "@medusajs/ui"
```
```tsx
<Command>
<code>yarn add @medusajs/ui</code>
</Command>
```
---
## API Reference
<ComponentReference mainComponent="Command" />
---
## Usage Outside Medusa Admin
If you're using the `Command` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree, as the `Command.Copy` component uses a [Tooltip](../tooltip/page.mdx#usage-outside-medusa-admin):
```tsx
<TooltipProvider>
<Command>
<code>yarn add @medusajs/ui</code>
<Command.Copy
content="yarn add @medusajs/ui"
className="ml-auto"
/>
</Command>
</TooltipProvider>
```
@@ -0,0 +1,38 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Container`,
}
# {metadata.title}
A component that wraps content in a card-like container. The container is useful to create sections in the Medusa Admin dashboard.
In this guide, you'll learn how to use the Container component.
<ComponentExample name="container-demo" />
## Usage
```tsx
import { Container } from "@medusajs/ui"
```
```tsx
<Container>Container</Container>
```
---
## API Reference
<ComponentReference mainComponent="Container" />
---
## Examples
### In a Layout
<ComponentExample name="container-layout" hideFeedback />
+56
View File
@@ -0,0 +1,56 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Copy`,
}
# {metadata.title}
A component that wraps content in a button with copy functionality. It is useful for quickly copying text to the clipboard, such as code snippets or configuration commands.
In this guide, you'll learn how to use the Copy component.
<ComponentExample name="copy-demo" />
## Usage
```tsx
import { Copy } from "@medusajs/ui"
```
```tsx
<Copy content="yarn add @medusajs/ui" />
```
---
## API Reference
<ComponentReference mainComponent="Copy" />
---
## Usage Outside Medusa Admin
If you're using the `Copy` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree, as the `Copy` component uses a [Tooltip](../tooltip/page.mdx#usage-outside-medusa-admin):
```tsx
<TooltipProvider>
<Copy content="yarn add @medusajs/ui" />
</TooltipProvider>
```
---
## Examples
### Copy with Custom Display
<ComponentExample name="copy-custom-display" />
### Copy Display As Child
Using the `asChild` prop, you can render the `<Copy/>` as its child. This is useful if you want to render a custom button, to prevent rendering a button inside a button.
<ComponentExample name="copy-as-child" hideFeedback />
@@ -0,0 +1,56 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Currency Input`,
}
# {metadata.title}
A component for rendering form inputs for money amounts, showing the currency in the input.
In this guide, you'll learn how to use the Currency Input component.
<ComponentExample name="currency-input-demo" />
## Usage
```tsx
import { CurrencyInput } from "@medusajs/ui"
```
```tsx
<CurrencyInput symbol="$" code="usd" />
```
---
## API Reference
<ComponentReference mainComponent="CurrencyInput" />
---
## Examples
### Controlled Currency Input
<ComponentExample name="currency-input-controlled" />
### Disabled Currency Input
<ComponentExample name="currency-input-disabled" />
### Currency Input with Error State
<ComponentExample name="currency-input-error" />
### Currency Input Sizes
#### Base
<ComponentExample name="currency-input-base" />
#### Small
<ComponentExample name="currency-input-small" hideFeedback />
@@ -0,0 +1,923 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
import { Feedback } from "@/components/Feedback"
export const metadata = {
title: `Data Table`,
}
# {metadata.title}
A component to display a table of data with advanced functionalities like pagination, filtering, and more.
In this guide, you'll learn how to use the DataTable component.
The `DataTable` component is useful if you're displaying large data with functionalities like pagination, filtering, sorting, and searching. It's also the recommended table component to use when creating customizations in the Medusa Admin.
<Note>
This component is available after Medusa UI v4.0.4 (or Medusa v2.4.0). It is built on top of the [Table](../table/page.mdx) component. If you want a table with more control over its styling and functionality, use that component instead.
</Note>
<ComponentExample name="data-table-demo" disableCenterAlignPreview />
## Usage
You import the `DataTable` component from `@medusajs/ui`.
```tsx
import {
DataTable,
} from "@medusajs/ui"
```
### Data Table Columns Preparation
Before using the `DataTable` component, you need to prepare its columns using the `createDataTableColumnHelper` utility:
```tsx
import {
// ...
createDataTableColumnHelper,
} from "@medusajs/ui"
const data = [
{
id: "1",
title: "Shirt",
price: 10,
},
// other data...
]
const columnHelper = createDataTableColumnHelper<typeof data[0]>()
const columns = [
columnHelper.accessor("title", {
header: "Title",
enableSorting: true,
}),
columnHelper.accessor("price", {
header: "Price",
}),
]
```
The `createDataTableColumnHelper` utility is a function that returns a helper used to generate column configurations for the `DataTable` component.
For each column in the table, use the `accessor` method of the column helper to specify configurations for a specific column. The `accessor` method accepts the column's key in the table's data as the first parameter, and an object with the following properties as the second parameter:
- `header`: The table header text for the column.
- `enableSorting`: (optional) A boolean that indicates whether data in the table can be sorted by this column. More on sorting in [this section](#configure-sorting-in-datatable).
### Create Data Table Instance
The `DataTable` component expects a table instance created using the `useDataTable` hook. Import that hook from `@medusajs/ui`:
```tsx
import {
// ...
useDataTable,
} from "@medusajs/ui"
```
Then, inside the component that will render `DataTable`, create a table instance using the `useDataTable` hook:
```tsx
export default function ProductTable() {
const table = useDataTable({
columns,
data,
getRowId: (product) => product.id,
rowCount: data.length,
isLoading: false,
})
}
```
The `useDataTable` hook accepts an object with the following properties:
- `columns`: An array of column configurations generated using the `createDataTableColumnHelper` utility.
- `data`: The data to be displayed in the table.
- `getRowId`: A function that returns the unique identifier of a row. The identifier must be a string.
- `rowCount`: The total number of rows in the table. If you're fetching data from the Medusa application with pagination or filters, this will be the total count, not the count of the data returned in the current page.
- `isLoading`: A boolean that indicates whether the table is loading data. This is useful when loading data from the Medusa application for the first time or in between pages.
### Render DataTable
Finally, render the `DataTable` component with the table instance created using the `useDataTable` hook:
```tsx
export default function ProductTable() {
// ...
return (
<DataTable instance={table}>
<DataTable.Toolbar className="flex flex-col items-start justify-between gap-2 md:flex-row md:items-center">
<Heading>Products</Heading>
</DataTable.Toolbar>
<DataTable.Table />
</DataTable>
)
}
```
In the `DataTable` component, you pass the following child components:
1. `DataTable.Toolbar`: The toolbar component shown at the top of the table. You can also add buttons for custom actions.
2. `DataTable.Table`: The table component that renders the data.
Refer to the examples later on this page to learn how to add pagination, filtering, and other functionalities using the `DataTable` component.
---
## API Reference
<ComponentReference mainComponent="DataTable" componentsToShow={[
"DataTable",
"DataTable.Table",
"DataTable.Pagination",
"DataTable.FilterMenu",
"DataTable.Search",
"DataTable.CommandBar",
"DataTable.SortingMenu",
]} />
---
## Example with Data Fetching
Refer to [this Admin Components guide](https://docs.medusajs.com/resources/admin-components/components/data-table) for an example on using the `DataTable` component with data fetching from the Medusa application.
---
## Handle Row Click
<ComponentExample name="data-table-row-click" disableCenterAlignPreview />
In many cases, you want to perform an action when a row is clicked. Most commonly, you may want to open the details page of the row when it's clicked.
<Note>
For bulk actions, such as deleting multiple rows, use the [Command Bar](#perform-bulk-actions-on-datatable-rows) instead.
</Note>
The `useDataTable` hook accepts an `onRowClick` property that you can use to handle row clicks:
```tsx
const navigate = useNavigate()
const table = useDataTable({
// ...
onRowClick(event, row) {
navigate(`/author/${row.id}`)
},
})
```
The value of `onRowClick` is a function that accepts two parameters:
- `event`: An instance of the [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) object.
- `row`: The data of the row that was clicked.
In the above example, you use a `navigate` function, retrieved through the `useNavigate` hook from `react-router-dom`, to navigate to the details page of the row that was clicked.
---
## Configure Cell Rendering
<ComponentExample name="data-table-custom-cell" disableCenterAlignPreview />
The `accessor` method of the `createDataTableColumnHelper` utility accepts a `cell` property that you can use to customize the rendering of the cell content.
For example:
```tsx
const products = [
{
id: "1",
title: "Shirt",
price: 10,
is_active: true,
},
{
id: "2",
title: "Pants",
price: 20,
is_active: true,
},
]
const columnHelper = createDataTableColumnHelper<typeof products[0]>()
const columns = [
columnHelper.accessor("is_active", {
header: "Status",
cell: ({ getValue }) => {
const isActive = getValue()
return (
<Badge color={isActive ? "green" : "grey"}>
{isActive ? "Active" : "Inactive"}
</Badge>
)
},
}),
// ...
]
```
The `cell` property's value is a function that returns a string or a React node to be rendered in the cell. The function receives as a parameter an object having a `getValue` property to get the raw value of the cell.
---
## Configure Search in DataTable
<ComponentExample name="data-table-search" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `search` property that you can use to enable and configure the search functionality in the `DataTable` component:
```tsx
// `useState` imported from `React`
const [search, setSearch] = useState("")
const table = useDataTable({
// ...
search: {
state: search,
onSearchChange: setSearch,
},
})
```
`search` accepts the following properties:
- `state`: The search query string. This must be a React state variable, as its value will be used for the table's search input.
- `onSearchChange`: A function that updates the search query string. Typically, this would be the setter function of the state variable, but you can also perform custom actions if necessary.
Next, you must implement the search filtering. For example, if you're retrieving data from the Medusa application, you pass the search query to the API to filter the data.
For example, when using a simple array as in the example above, this is how you filter the data by the search query:
```tsx
const [search, setSearch] = useState<string>("")
const shownProducts = useMemo(() => {
return products.filter((product) => product.title.toLowerCase().includes(search.toLowerCase()))
}, [search])
const table = useDataTable({
columns,
data: shownProducts,
getRowId: (product) => product.id,
rowCount: products.length,
isLoading: false,
// Pass the state and onSearchChange to the table instance.
search: {
state: search,
onSearchChange: setSearch,
},
})
```
Then, render the `DataTable.Search` component as part of the `DataTable`'s children:
```tsx
return (
<DataTable instance={table}>
<DataTable.Toolbar className="flex flex-col items-start justify-between gap-2 md:flex-row md:items-center">
<Heading>Products</Heading>
{/* This component renders the search bar */}
<DataTable.Search placeholder="Search..." />
</DataTable.Toolbar>
<DataTable.Table />
</DataTable>
)
```
This will show a search input at the top of the table, in the data table's toolbar.
---
## Configure Pagination in DataTable
<ComponentExample name="data-table-pagination" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `pagination` property that you can use to enable and configure the pagination functionality in the `DataTable` component.
First, import the `DataTablePaginationState` type from `@medusajs/ui`:
```tsx
import {
// ...
DataTablePaginationState,
} from "@medusajs/ui"
```
Then, create a state variable to manage the pagination:
```tsx
const [pagination, setPagination] = useState<DataTablePaginationState>({
pageSize: 15,
pageIndex: 0,
})
```
The pagination state variable of type `DataTablePaginationState` is an object with the following properties:
- `pageSize`: The number of rows to display per page.
- `pageIndex`: The current page index. It's zero-based, meaning the first page would be `0`.
Next, pass the pagination object to the `useDataTable` hook:
```tsx
const table = useDataTable({
// ...
pagination: {
state: pagination,
onPaginationChange: setPagination,
},
})
```
`pagination` accepts the following properties:
- `state`: The pagination state object. This must be a React state variable of type `DataTablePaginationState`.
- `onPaginationChange`: A function that updates the pagination state object. Typically, this would be the setter function of the state variable, but you can also perform custom actions if necessary.
You must also implement the pagination logic, such as fetching data from the Medusa application with the pagination parameters.
For example, when using a simple array as in the example above, this is how you paginate the data:
```tsx
const [pagination, setPagination] = useState<DataTablePaginationState>({
pageSize: PAGE_SIZE,
pageIndex: 0,
})
const shownProducts = useMemo(() => {
return products.slice(
pagination.pageIndex * pagination.pageSize,
(pagination.pageIndex + 1) * pagination.pageSize
)
}, [pagination])
const table = useDataTable({
data: shownProducts,
columns,
rowCount: products.length,
getRowId: (product) => product.id,
pagination: {
// Pass the pagination state and updater to the table instance
state: pagination,
onPaginationChange: setPagination,
},
isLoading: false,
})
```
Finally, render the `DataTable.Pagination` component as part of the `DataTable`'s children:
```tsx
return (
<DataTable instance={table}>
<DataTable.Toolbar>
<Heading>Products</Heading>
</DataTable.Toolbar>
<DataTable.Table />
{/** This component will render the pagination controls **/}
<DataTable.Pagination />
</DataTable>
)
```
This will show the pagination controls at the end of the table.
---
## Configure Filters in DataTable
<ComponentExample name="data-table-filters" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `filters` property that you can use to enable and configure the filtering functionality in the `DataTable` component.
First, add the following imports from the `@medusajs/ui` package:
```tsx
import {
// ...
createDataTableFilterHelper,
DataTableFilteringState,
} from "@medusajs/ui"
```
The `createDataTableFilterHelper` utility is a function that returns a helper function to generate filter configurations for the `DataTable` component. The `DataTableFilteringState` type is an object that represents the filtering state of the table.
Then, create the filters using the `createDataTableFilterHelper` utility:
<Note title="Tip">
Create the filters outside the component rendering the `DataTable` component.
</Note>
```tsx
const filterHelper = createDataTableFilterHelper<typeof products[0]>()
const filters = [
filterHelper.accessor("title", {
type: "select",
label: "Title",
options: products.map((product) => ({
label: product.title,
value: product.title.toLowerCase(),
})),
}),
]
```
The filter helper returned by `createDataTableFilterHelper` has an `accessor` method that accepts the column's key in the data as the first parameter, and an object with the following properties as the second parameter:
- `type`: The type of filter. It can be either:
- `select`: A select dropdown filter.
- `radio`: A radio button filter.
- `date`: A date filter.
- `label`: The label text for the filter.
- `options`: If the filter type is `select` or `radio`, an array of dropdown options. Each option has a `label` and `value` property.
<Note>
Refer to [this section](#filtering-date-values) to learn how to use date filters.
</Note>
Next, in the component rendering the `DataTable` component, create a state variable to manage the filtering, and pass the filters to the `useDataTable` hook:
```tsx
const [filtering, setFiltering] = useState<DataTableFilteringState>({})
const table = useDataTable({
// ...
filters,
filtering: {
state: filtering,
onFilteringChange: setFiltering,
},
})
```
You create a `filtering` state variable of type `DataTableFilteringState` to manage the filtering state. You can also set initial filters as explained in [this section](#initial-filter-values).
The `useDataTable` hook accepts the following properties for filtering:
- `filters`: An array of filter configurations generated using the `createDataTableFilterHelper` utility.
- `filtering`: An object with the following properties:
- `state`: The filtering state object. This must be a React state variable of type `DataTableFilteringState`.
- `onFilteringChange`: A function that updates the filtering state object. Typically, this would be the setter function of the state variable, but you can also perform custom actions if necessary.
You must also implement the logic of filtering the data based on the filter conditions, such as sending the filter conditions to the Medusa application when fetching data.
For example, when using a simple array as in the example above, this is how you filter the data based on the filter conditions:
```tsx
const [filtering, setFiltering] = useState<DataTableFilteringState>({})
const shownProducts = useMemo(() => {
return products.filter((product) => {
return Object.entries(filtering).every(([key, value]) => {
if (!value) {
return true
}
if (typeof value === "string") {
// @ts-ignore
return product[key].toString().toLowerCase().includes(value.toString().toLowerCase())
}
if (Array.isArray(value)) {
// @ts-ignore
return value.includes(product[key].toLowerCase())
}
if (typeof value === "object") {
// @ts-ignore
const date = new Date(product[key])
let matching = false
if ("$gte" in value && value.$gte) {
matching = date >= new Date(value.$gte as number)
}
if ("$lte" in value && value.$lte) {
matching = date <= new Date(value.$lte as number)
}
if ("$lt" in value && value.$lt) {
matching = date < new Date(value.$lt as number)
}
if ("$gt" in value && value.$gt) {
matching = date > new Date(value.$gt as number)
}
return matching
}
})
})
}, [filtering])
const table = useDataTable({
data: shownProducts,
columns,
getRowId: (product) => product.id,
rowCount: products.length,
isLoading: false,
filtering: {
state: filtering,
onFilteringChange: setFiltering,
},
filters,
})
```
When filters are selected, the `filtering` state object will contain the filter conditions, where the key is the column key and the value can be:
- `undefined` if the user is still selecting the value.
- A string if the filter type is `radio`, as the user can choose only one value.
- An array of strings if the filter type is `select`, as the user can choose multiple values.
- An object with the filter conditions if the filter type is `date`. The filter conditions for dates are explained more in [this section](#filtering-date-values).
Finally, render the `DataTable.FilterMenu` component as part of the `DataTable`'s children:
```tsx
return (
<DataTable instance={table}>
<DataTable.Toolbar className="flex justify-between items-center">
<Heading>Products</Heading>
{/** This component will render a menu that allows the user to choose which filters to apply to the table data. **/}
<DataTable.FilterMenu tooltip="Filter" />
</DataTable.Toolbar>
<DataTable.Table />
</DataTable>
)
```
This will show a filter menu at the top of the table, in the data table's toolbar.
### Filtering Date Values in DataTable
<ComponentExample name="data-table-filters-date" disableCenterAlignPreview />
Consider your data has a `created_at` field that contains date values. To filter the data based on date values, you can add a `date` filter using the filter helper:
```tsx
const filters = [
// ...
filterHelper.accessor("created_at", {
type: "date",
label: "Created At",
format: "date",
formatDateValue: (date) => date.toLocaleString(),
rangeOptionStartLabel: "From",
rangeOptionEndLabel: "To",
rangeOptionLabel: "Between",
options: [
{
label: "Today",
value: {
$gte: new Date(new Date().setHours(0, 0, 0, 0)).toString(),
$lte: new Date(new Date().setHours(23, 59, 59, 999)).toString(),
},
},
{
label: "Yesterday",
value: {
$gte: new Date(new Date().setHours(0, 0, 0, 0) - 24 * 60 * 60 * 1000).toString(),
$lte: new Date(new Date().setHours(0, 0, 0, 0)).toString(),
},
},
{
label: "Last Week",
value: {
$gte: new Date(new Date().setHours(0, 0, 0, 0) - 7 * 24 * 60 * 60 * 1000).toString(),
$lte: new Date(new Date().setHours(0, 0, 0, 0)).toString(),
},
},
],
}),
]
```
When the filter type is `date`, the filter configuration object passed as a second parameter to the `accessor` method accepts the following properties:
- `format`: The format of the date value. It can be either `date` to filter by dates, or `datetime` to filter by dates and times.
- `formatDateValue`: A function that formats the date value when displaying it in the filter options.
- `rangeOptionStartLabel`: (optional) The label for the start date input in the range filter.
- `rangeOptionEndLabel`: (optional) The label for the end date input in the range filter.
- `rangeOptionLabel`: (optional) The label for the range filter option.
- `options`: By default, the filter will allow the user to filter between two dates. You can also set this property to an array of filter options to quickly choose from. Each option has a `label` and `value` property. The `value` property is an object that represents the filter condition. In this example, the filter condition is an object with a `$gte` property that specifies the date that the data should be greater than or equal to. Allowed properties are:
- `$gt`: Greater than.
- `$lt`: Less than.
- `$lte`: Less than or equal to.
- `$gte`: Greater than or equal to.
When the user selects a date filter option, the `filtering` state object will contain the filter conditions, where the key is the column key and the value is an object with the filter conditions. You must handle the filter logic as explained earlier.
For example, when using a simple array as in the example above, this is how you filter the data based on the date filter conditions:
```tsx
const shownProducts = useMemo(() => {
return products.filter((product) => {
return Object.entries(filtering).every(([key, value]) => {
if (!value) {
return true
}
// other types checks...
if (typeof value === "object") {
// @ts-ignore
const date = new Date(product[key])
let matching = false
if ("$gte" in value && value.$gte) {
matching = date >= new Date(value.$gte as number)
}
if ("$lte" in value && value.$lte) {
matching = date <= new Date(value.$lte as number)
}
if ("$lt" in value && value.$lt) {
matching = date < new Date(value.$lt as number)
}
if ("$gt" in value && value.$gt) {
matching = date > new Date(value.$gt as number)
}
return matching
}
})
})
}, [filtering])
```
### Initial Filter Values in DataTable
<ComponentExample name="data-table-filters-initial" disableCenterAlignPreview />
If you want to set initial filter values, you can set the initial state of the `filtering` state variable:
```tsx
const [filtering, setFiltering] = useState<DataTableFilteringState>({
title: ["shirt"],
})
```
The user can still change the filter values, but the initial values will be applied when the table is first rendered.
---
## Configure Sorting in DataTable
<ComponentExample name="data-table-sorting" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `sorting` property that you can use to enable and configure the sorting functionality in the `DataTable` component.
First, in the `columns` array created by the columns helper, specify for the sortable columns the following properties:
```tsx
const columns = [
columnHelper.accessor("title", {
header: "Title",
// Enables sorting for the column.
enableSorting: true,
// If omitted, the header will be used instead if it's a string,
// otherwise the accessor key (id) will be used.
sortLabel: "Title",
// If omitted the default value will be "A-Z"
sortAscLabel: "A-Z",
// If omitted the default value will be "Z-A"
sortDescLabel: "Z-A",
}),
]
```
The `accessor` method of the helper function accepts the following properties for sorting:
- `enableSorting`: A boolean that indicates whether data in the table can be sorted by this column.
- `sortLabel`: The label text for the sort button in the column header. If omitted, the `header` will be used instead if it's a string, otherwise the accessor key (id) will be used.
- `sortAscLabel`: The label text for the ascending sort button. If omitted, the default value will be `A-Z`.
- `sortDescLabel`: The label text for the descending sort button. If omitted, the default value will be `Z-A`.
Next, in the component rendering the `DataTable` component, create a state variable to manage the sorting, and pass the sorting object to the `useDataTable` hook:
```tsx
import {
// ...
DataTableSortingState,
} from "@medusajs/ui"
export default function ProductTable() {
const [sorting, setSorting] = useState<DataTableSortingState | null>(null)
const table = useDataTable({
// ...
sorting: {
state: sorting,
onSortingChange: setSorting,
},
})
// ...
}
```
You create a state variable of type `DataTableSortingState` to manage the sorting state. You can also set initial sorting values as explained in [this section](#initial-sort-values).
The `sorting` object passed to the `useDataTable` hook accepts the following properties:
- `state`: The sorting state object. This must be a React state variable of type `DataTableSortingState`.
- `onSortingChange`: A function that updates the sorting state object. Typically, this would be the setter function of the state variable, but you can also perform custom actions if necessary.
You must also implement the sorting logic, such as sending the sorting conditions to the Medusa application when fetching data.
For example, when using a simple array as in the example above, this is how you sort the data based on the sorting conditions:
```tsx
const [sorting, setSorting] = useState<DataTableSortingState | null>(null)
const shownProducts = useMemo(() => {
if (!sorting) {
return products
}
return products.slice().sort((a, b) => {
// @ts-ignore
const aVal = a[sorting.id]
// @ts-ignore
const bVal = b[sorting.id]
if (aVal < bVal) {
return sorting.desc ? 1 : -1
}
if (aVal > bVal) {
return sorting.desc ? -1 : 1
}
return 0
})
}, [sorting])
const table = useDataTable({
data: shownProducts,
columns,
getRowId: (product) => product.id,
rowCount: products.length,
sorting: {
// Pass the pagination state and updater to the table instance
state: sorting,
onSortingChange: setSorting,
},
isLoading: false,
})
```
The `sorting` state object has the following properties:
- `id`: The column key to sort by.
- `desc`: A boolean that indicates whether to sort in descending order.
Finally, render the `DataTable.SortingMenu` component as part of the `DataTable`'s children:
```tsx
return (
<DataTable instance={table}>
<DataTable.Toolbar className="flex justify-between items-center">
<Heading>Products</Heading>
{/** This component will render a menu that allows the user to choose which column to sort by and in what direction. **/}
<DataTable.SortingMenu tooltip="Sort" />
</DataTable.Toolbar>
<DataTable.Table />
</DataTable>
)
```
This will show a sorting menu at the top of the table, in the data table's toolbar.
### Initial Sort Values in DataTable
<ComponentExample name="data-table-sorting-initial" disableCenterAlignPreview />
If you want to set initial sort values, you can set the initial state of the `sorting` state variable:
```tsx
const [sorting, setSorting] = useState<DataTableSortingState | null>({
id: "title",
desc: false,
})
```
The user can still change the sort values, but the initial values will be applied when the table is first rendered.
---
## Perform Bulk Actions on DataTable Rows
<ComponentExample name="data-table-commands" disableCenterAlignPreview />
The object passed to the `useDataTable` hook accepts a `commands` object property that you can use to add custom actions to the `DataTable` component.
First, add the following imports from `@medusajs/ui`:
```tsx
import {
// ...
createDataTableCommandHelper,
DataTableRowSelectionState,
} from "@medusajs/ui"
```
The `createDataTableCommandHelper` utility is a function that returns a helper function to generate command configurations for the `DataTable` component. The `DataTableRowSelectionState` type is an object that represents the row selection state of the table.
Then, in the `columns` array created by the columns helper, add a `select` column:
```tsx
const columns = [
// Commands requires a select column.
columnHelper.select(),
// ...
]
```
The `select` method of the helper function adds a select column to the table. This column will render checkboxes in each row to allow the user to select rows.
Next, create the commands using the `createDataTableCommandHelper` utility:
<Note title="Tip">
Create the commands outside the component rendering the `DataTable` component.
</Note>
```tsx
const commandHelper = createDataTableCommandHelper()
const useCommands = () => {
return [
commandHelper.command({
label: "Delete",
shortcut: "D",
action: async (selection) => {
const productsToDeleteIds = Object.keys(selection)
// TODO remove products from the server
},
}),
]
}
```
The `createDataTableCommandHelper` utility is a function that returns a helper function to generate command configurations for the `DataTable` component.
You create a function that returns an array of command configurations. This is useful if the command's action requires initializing other functions or hooks.
The `command` method of the helper function accepts the following properties:
- `label`: The label text for the command.
- `shortcut`: The keyboard shortcut for the command. This shortcut only works when rows are selected in the table.
- `action`: A function that performs the action when the command is executed. The function receives the selected rows as an object, where the key is the row's `id` field and the value is a boolean indicating that the row is selected. You can send a request to the server within this function to perform the action.
Then, in the component rendering the `DataTable` component, create a state variable to manage the selected rows, and pass the commands to the `useDataTable` hook:
```tsx
const [rowSelection, setRowSelection] = useState<DataTableRowSelectionState>({})
const commands = useCommands()
const instance = useDataTable({
data: products,
columns,
getRowId: (product) => product.id,
rowCount: products.length,
isLoading: false,
commands,
rowSelection: {
state: rowSelection,
onRowSelectionChange: setRowSelection,
},
})
```
You create a state variable of type `DataTableRowSelectionState` to manage the selected rows. You also retrieve the commands by calling the `useCommand` function.
The `useDataTable` hook accepts the following properties for commands:
- `commands`: An array of command configurations generated using the `createDataTableCommandHelper` utility.
- `rowSelection`: An object that enables selecting rows in the table. It accepts the following properties:
- `state`: The row selection state object. This must be a React state variable of type `DataTableRowSelectionState`.
- `onRowSelectionChange`: A function that updates the row selection state object. Typically, this would be the setter function of the state variable, but you can also perform custom actions if necessary.
Finally, render the `DataTable.CommandBar` component as part of the `DataTable`'s children:
```tsx
return (
<DataTable instance={instance}>
<DataTable.Toolbar className="flex justify-between items-center">
<Heading>Products</Heading>
</DataTable.Toolbar>
<DataTable.Table />
{/** This component will the command bar when the user has selected at least one row. **/}
<DataTable.CommandBar selectedLabel={(count) => `${count} selected`} />
</DataTable>
)
```
This will show a command bar when the user has selected at least one row in the table.
@@ -0,0 +1,74 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Date Picker`,
}
# {metadata.title}
A component for rendering date picker inputs with range and presets.
In this guide, you'll learn how to use the Date Picker component.
<ComponentExample name="date-picker-demo" />
## Usage
```tsx
import { DatePicker } from "@medusajs/ui"
```
```tsx
<DatePicker />
```
---
## API Reference
<ComponentReference mainComponent="DatePicker" />
---
## Examples
### Controlled Date Picker
Manage and store the value of the date picker in a state variable for controlled behavior. This is also useful for form integration.
<ComponentExample name="date-picker-controlled" />
### Date Picker With Time
Enable time selection with different granularity levels for precise scheduling.
<ComponentExample name="date-picker-with-time" />
### Date Picker Min/Max Values
Restrict date selection to a specific range by setting minimum and maximum values.
In the example below, you can only select dates within the next 30 days. Dates outside the range are disabled.
<ComponentExample name="date-picker-min-max" />
### Date Picker Disabled Dates
Disable specific dates like weekends and holidays to prevent selection of unavailable dates.
The example below disables weekends and holidays like Christmas.
<ComponentExample name="date-picker-business-hours" />
### Date Picker Granularity Options
Different levels of time precision from date-only to second-precision selection.
<ComponentExample name="date-picker-granularity" />
### Date Picker Form Integration
The following example shows how to use the date picker in a form, with simulated form submission.
<ComponentExample name="date-picker-form" hideFeedback />
@@ -0,0 +1,61 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Drawer`,
}
# {metadata.title}
A component for rendering a sliding panel that overlays the main content.
In this guide, you'll learn how to use the Drawer component.
<ComponentExample name="drawer-demo" />
## Usage
```tsx
import { Drawer } from "@medusajs/ui"
```
```tsx
<Drawer>
<Drawer.Trigger>Trigger</Drawer.Trigger>
<Drawer.Content>
<Drawer.Header>
<Drawer.Title>Drawer Title</Drawer.Title>
</Drawer.Header>
<Drawer.Body>Body</Drawer.Body>
<Drawer.Footer>Footer</Drawer.Footer>
</Drawer.Content>
</Drawer>
```
---
## API Reference
<ComponentReference mainComponent="Drawer" componentsToShow={[
"Drawer",
"Drawer.Trigger",
"Drawer.Content",
"Drawer.Header",
"Drawer.Title",
"Drawer.Body",
"Drawer.Footer"
]} />
---
## Examples
### Drawer with Form
This example shows a simple form inside a Drawer, demonstrating how to use form elements and handle submission.
<ComponentExample name="drawer-form" hideFeedback />
@@ -0,0 +1,79 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
import { getOsShortcut, Kbd } from "docs-ui"
export const osShortcut = getOsShortcut()
export const metadata = {
title: `Dropdown Menu`,
}
# {metadata.title}
A component for rendering dropdown menus that display a set of actions or options to users.
In this guide, you'll learn how to use the Dropdown Menu component.
<ComponentExample name="dropdown-menu-demo" />
## Usage
```tsx
import { DropdownMenu } from "@medusajs/ui"
```
```tsx
<DropdownMenu>
<DropdownMenu.Trigger>Trigger</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Item>Edit</DropdownMenu.Item>
<DropdownMenu.Item>Add</DropdownMenu.Item>
<DropdownMenu.Item>Delete</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>
```
---
## API Reference
<ComponentReference mainComponent="DropdownMenu" componentsToShow={[
"DropdownMenu",
"DropdownMenu.Trigger",
"DropdownMenu.Content",
"DropdownMenu.Item",
"DropdownMenu.Shortcut",
"DropdownMenu.Hint",
"DropdownMenu.RadioGroup",
"DropdownMenu.RadioItem"
]} />
---
## Examples
### Sorting
This example shows how to display collection sorting choices using a Dropdown Menu.
<ComponentExample name="dropdown-menu-sorting" />
### Dropdown with Submenu
<ComponentExample name="dropdown-menu-submenu" />
### Disabled Items and Using Icons
<ComponentExample name="dropdown-menu-disabled-icons" />
### Keyboard Shortcuts (with handling)
This example shows how to visually display keyboard shortcuts in the menu and handle them in your application logic.
You can use the <Kbd>{osShortcut}E</Kbd> and <Kbd>{osShortcut}D</Kbd> shortcuts to trigger the actions of the dropdown items.
<ComponentExample name="dropdown-menu-shortcuts" hideFeedback />
@@ -0,0 +1,66 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Focus Modal`,
}
# {metadata.title}
A component for rendering a modal dialog shown over the main content.
In this guide, you'll learn how to use the Focus Modal component.
<ComponentExample name="focus-modal-demo" />
## Usage
```tsx
import { FocusModal } from "@medusajs/ui"
```
```tsx
<FocusModal>
<FocusModal.Trigger>Trigger</FocusModal.Trigger>
<FocusModal.Content>
<FocusModal.Header>Title</FocusModal.Header>
<FocusModal.Body>Content</FocusModal.Body>
</FocusModal.Content>
</FocusModal>
```
---
## API Reference
<ComponentReference mainComponent="FocusModal" componentsToShow={[
"FocusModal",
"FocusModal.Trigger",
"FocusModal.Content",
"FocusModal.Header",
"FocusModal.Body",
"FocusModal.Footer"
]} />
---
## Examples
### Control Focus Modal Open State
<ComponentExample name="focus-modal-controlled" />
### Using Form in Focus Modal
<ComponentExample name="focus-modal-form" />
### Nested Focus Modals
A focus modal can open another focus modal. These focus modals will be stacked on top of each other. You can nest as many focus modals as you want.
<ComponentExample name="focus-modal-nested" hideFeedback />
@@ -0,0 +1,30 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Heading`,
}
# {metadata.title}
A component used for page titles and other headers.
In this guide, you'll learn how to use the Heading component.
<ComponentExample name="heading-demo" />
## Usage
```tsx
import { Heading } from "@medusajs/ui"
```
```tsx
<Heading>A Title</Heading>
```
---
## API Reference
<ComponentReference mainComponent="Heading" hideFeedback />
@@ -0,0 +1,45 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Icon Badge`,
}
# {metadata.title}
A component that displays an icon in a badge.
In this guide, you'll learn how to use the Icon Badge component.
<ComponentExample name="icon-badge-demo" />
## Usage
```tsx
import { IconBadge } from "@medusajs/ui"
import { BuildingTax } from "@medusajs/icons"
```
```tsx
<IconBadge>
<BuildingTax />
</IconBadge>
```
---
## API Reference
<ComponentReference mainComponent="IconBadge" />
---
## Examples
### Colors
<ComponentExample name="icon-badge-all-colors" />
### Sizes
<ComponentExample name="icon-badge-all-sizes" hideFeedback />
@@ -0,0 +1,55 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Icon Button`,
}
# {metadata.title}
A component that displays an icon in a button.
In this guide, you'll learn how to use the Icon Button component.
<ComponentExample name="icon-button-demo" />
## Usage
```tsx
import { IconButton } from "@medusajs/ui"
import { Plus } from "@medusajs/icons"
```
```tsx
<IconButton>
<Plus />
</IconButton>
```
---
## API Reference
<ComponentReference mainComponent="IconButton" />
---
## Examples
### Icon Button Variants
<ComponentExample name="icon-button-all-variants" />
### Icon Button Sizes
<ComponentExample name="icon-button-all-sizes" />
### Icon Button Loading State
<ComponentExample name="icon-button-loading" />
### Disabled Icon Button
<ComponentExample name="icon-button-disabled" hideFeedback />
@@ -0,0 +1,50 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Inline Tip`,
}
# {metadata.title}
A component for displaying a note or tip inline.
In this guide, you'll learn how to use the Inline Tip component.
<ComponentExample name="inline-tip-demo" />
## Usage
```tsx
import { InlineTip } from "@medusajs/ui"
```
```tsx
<InlineTip
label="This is a tip"
>
<button>Hover me</button>
</InlineTip>
```
---
## API Reference
<ComponentReference mainComponent="InlineTip" />
---
## Examples
### Success Inline Tip
<ComponentExample name="inline-tip-success" />
### Warning Inline Tip
<ComponentExample name="inline-tip-warning" />
### Error Inline Tip
<ComponentExample name="inline-tip-error" hideFeedback />
+60
View File
@@ -0,0 +1,60 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Input`,
}
# {metadata.title}
A component that renders a form input field using Medusa's design system.
In this guide, you'll learn how to use the Input component.
<ComponentExample name="input-demo" />
## Usage
```tsx
import { Input } from "@medusajs/ui"
```
```tsx
<Input placeholder="Placeholder" id="input-id" />
```
---
## API Reference
<ComponentReference mainComponent="Input" />
---
## Examples
### Password
<ComponentExample name="input-password" />
### Search
<ComponentExample name="input-search" />
### Disabled
<ComponentExample name="input-disabled" />
### Small Size
<ComponentExample name="input-small" />
### Controlled
<ComponentExample name="input-controlled" />
### Error State
You can leverage the native `aria-invalid` property to show an error state on your input:
<ComponentExample name="input-error" hideFeedback />
+30
View File
@@ -0,0 +1,30 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Kbd`,
}
# {metadata.title}
A component that renders a badge-styled keyboard (`kbd`) element.
In this guide, you'll learn how to use the Kbd component.
<ComponentExample name="kbd-demo" />
## Usage
```tsx
import { Kbd } from "@medusajs/ui"
```
```tsx
<Kbd>Ctrl + Shift + A</Kbd>
```
---
## API Reference
<ComponentReference mainComponent="Kbd" hideFeedback />
+42
View File
@@ -0,0 +1,42 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Label`,
}
# {metadata.title}
A component that renders an accessible label associated with input fields.
In this guide, you'll learn how to use the Label component.
<ComponentExample name="label-demo" />
## Usage
```tsx
import { Label } from "@medusajs/ui"
```
```tsx
<Label>Label</Label>
```
---
## API Reference
<ComponentReference mainComponent="Label" />
---
## Examples
### Label Sizes
<ComponentExample name="label-all-sizes" />
### Label with Form Inputs
<ComponentExample name="label-with-inputs" hideFeedback />
@@ -0,0 +1,78 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Progress Accordion`,
}
# {metadata.title}
A component that renders a set of expandable content, specifically designed for implementing multi-step tasks.
In this guide, you'll learn how to use the Progress Accordion component.
<ComponentExample name="progress-accordion-demo" />
## Usage
```tsx
import { ProgressAccordion } from "@medusajs/ui"
```
```tsx
<ProgressAccordion type="single">
<ProgressAccordion.Item value="general">
<ProgressAccordion.Header>
General
</ProgressAccordion.Header>
<ProgressAccordion.Content>
{/* Content */}
</ProgressAccordion.Content>
</ProgressAccordion.Item>
<ProgressAccordion.Item value="shipping">
<ProgressAccordion.Header>
Shipping
</ProgressAccordion.Header>
<ProgressAccordion.Content>
{/* Content */}
</ProgressAccordion.Content>
</ProgressAccordion.Item>
</ProgressAccordion>
```
---
## API Reference
<ComponentReference mainComponent="ProgressAccordion" componentsToShow={[
"ProgressAccordion",
"ProgressAccordion.Header"
]} />
---
## Examples
### Only One Accordion Open
<ComponentExample name="progress-accordion-single" />
### Allow Multiple Accordions to Open
<ComponentExample name="progress-accordion-multiple" />
### Set Status Indicator
<ComponentExample name="progress-accordion-status" />
### Controlled Accordion Open State
<ComponentExample name="progress-accordion-controlled" />
### Disabled Accordion Item
<ComponentExample name="progress-accordion-disabled" hideFeedback />
@@ -0,0 +1,74 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Progress Tabs`,
}
# {metadata.title}
A component that renders tabbed content, specifically designed for implementing multi-step tasks.
In this guide, you'll learn how to use the Progress Tabs component.
<ComponentExample name="progress-tabs-demo" />
## Usage
```tsx
import { ProgressTabs } from "@medusajs/ui"
```
```tsx
<ProgressTabs defaultValue="general">
<ProgressTabs.List>
<ProgressTabs.Trigger value="general">
General
</ProgressTabs.Trigger>
<ProgressTabs.Trigger value="shipping">
Shipping
</ProgressTabs.Trigger>
<ProgressTabs.Trigger value="payment">
Payment
</ProgressTabs.Trigger>
</ProgressTabs.List>
<ProgressTabs.Content value="general">
{/* Content */}
</ProgressTabs.Content>
<ProgressTabs.Content value="shipping">
{/* Content */}
</ProgressTabs.Content>
<ProgressTabs.Content value="payment">
{/* Content */}
</ProgressTabs.Content>
</ProgressTabs>
```
---
## API Reference
<ComponentReference mainComponent="ProgressTabs" componentsToShow={[
"ProgressTabs",
"ProgressTabs.Trigger",
]} />
---
## Examples
### Set Status Indicator
<ComponentExample name="progress-tabs-status" />
### Controlled Active Tab
<ComponentExample name="progress-tabs-controlled" />
### Disabled Tab
<ComponentExample name="progress-tabs-disabled" hideFeedback />
@@ -0,0 +1,66 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Prompt`,
}
# {metadata.title}
A component that displays a dialog prompting the user for their approval. It's useful when confirming destructive actions.
<Note>
This component is useful if you want to control the prompt's content, format, and design. For a simpler approach that follows Medusa's prompt format, refer to the [usePrompt hook](../../hooks/use-prompt/page.mdx).
</Note>
In this guide, you'll learn how to use the Prompt component.
<ComponentExample name="prompt-demo" />
## Usage
```tsx
import { Prompt } from "@medusajs/ui"
```
```tsx
<Prompt>
<Prompt.Trigger>Trigger</Prompt.Trigger>
<Prompt.Content>
<Prompt.Header>
<Prompt.Title>Title</Prompt.Title>
<Prompt.Description>Description</Prompt.Description>
</Prompt.Header>
<Prompt.Footer>
<Prompt.Cancel>Cancel</Prompt.Cancel>
<Prompt.Action>Delete</Prompt.Action>
</Prompt.Footer>
</Prompt.Content>
</Prompt>
```
---
## API Reference
<ComponentReference mainComponent="Prompt" componentsToShow={[
"Prompt",
"Prompt.Header",
"Prompt.Footer"
]} />
---
## Examples
### Confirmation Prompt Variant
The `confirmation` variant is useful when confirming an operation that isn't destructive, such as deleting an item.
<ComponentExample name="prompt-confirmation" hideFeedback />
@@ -0,0 +1,60 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Radio Group`,
}
# {metadata.title}
A component that renders a group of radio buttons using Medusa's design system.
In this guide, you'll learn how to use the Radio Group component.
<ComponentExample name="radio-group-demo" />
## Usage
```tsx
import { RadioGroup } from "@medusajs/ui"
```
```tsx
<RadioGroup>
<RadioGroup.Item value="1" id="radio_1" />
<RadioGroup.Item value="2" id="radio_2" />
<RadioGroup.Item value="3" id="radio_3" />
</RadioGroup>
```
---
## API Reference
<ComponentReference mainComponent="RadioGroup" />
---
## Examples
### Radio Group with Descriptions
<ComponentExample name="radio-group-descriptions" />
### Controlled Radio Group
<ComponentExample name="radio-group-controlled" />
### Radio Group with a Disabled Item
<ComponentExample name="radio-group-disabled" />
---
## Radio Choice Box
The `RadioGroup.ChoiceBox` component allows you to show a group of radio buttons, each in a box with a label and description.
<ComponentExample name="radio-group-choicebox" hideFeedback />
{/* TODO add API reference */}
@@ -0,0 +1,77 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Select`,
}
# {metadata.title}
A component that displays a select form input using Medusa's design system.
In this guide, you'll learn how to use the Select component.
<ComponentExample name="select-demo" />
## Usage
```tsx
import { Select } from "@medusajs/ui"
```
```tsx
<Select>
<Select.Trigger>
<Select.Value placeholder="Placeholder" />
</Select.Trigger>
<Select.Content>
{items.map((item) => (
<Select.Item key={item.value} value={item.value}>
{item.label}
</Select.Item>
))}
</Select.Content>
</Select>
```
---
## API Reference
<ComponentReference mainComponent="Select" componentsToShow={[
"Select",
"Select.Trigger",
"Select.Value",
"Select.Group",
"Select.Label",
"Select.Item",
"Select.Content"
]} />
---
## Examples
### Small Select
<ComponentExample name="select-small" />
### Select Item-Aligned Position
<ComponentExample name="select-item-aligned" />
### Disabled Select
<ComponentExample name="select-disabled" />
### Select with Grouped Items
<ComponentExample name="select-grouped-items" />
### Controlled Select
<ComponentExample name="select-controlled" hideFeedback />
@@ -0,0 +1,38 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Status Badge`,
}
# {metadata.title}
A component that displays the status of an item in a badge style. It's useful to indicate states like "Active", "Published", or "Draft".
In this guide, you'll learn how to use the Status Badge component.
<ComponentExample name="status-badge-demo" />
## Usage
```tsx
import { StatusBadge } from "@medusajs/ui"
```
```tsx
<StatusBadge color="green">Active</StatusBadge>
```
---
## API Reference
<ComponentReference mainComponent="StatusBadge" />
---
## Examples
### Status Badge Colors
<ComponentExample name="status-badge-all-colors" hideFeedback />
@@ -0,0 +1,46 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Switch`,
}
# {metadata.title}
A component for toggling between two states, typically on and off. It's essentially a checkbox in the form of a switch.
In this guide, you'll learn how to use the Switch component.
<ComponentExample name="switch-demo" />
## Usage
```tsx
import { Switch } from "@medusajs/ui"
```
```tsx
<Switch />
```
---
## API Reference
<ComponentReference mainComponent="Switch" />
---
## Examples
### Switch Sizes
<ComponentExample name="switch-all-sizes" />
### Controlled Switch
<ComponentExample name="switch-controlled" hideFeedback />
### Disabled Switch
<ComponentExample name="switch-disabled" />
+66
View File
@@ -0,0 +1,66 @@
---
generate_toc: true
---
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Table`,
}
# {metadata.title}
A component that displays data in a structured table format.
In this guide, you'll learn how to use the Table component.
<Note>
If you're looking to add a table to your Medusa Admin customizations with advanced features like filters, search, sorting, and bulk actions, refer to the [DataTable](../data-table/page.mdx) component instead.
</Note>
<ComponentExample name="table-demo" />
## Usage
```tsx
import { Table } from "@medusajs/ui"
```
```tsx
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>#</Table.HeaderCell>
<Table.HeaderCell>Customer</Table.HeaderCell>
<Table.HeaderCell>Email</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>1</Table.Cell>
<Table.Cell>Emil Larsson</Table.Cell>
<Table.Cell>emil2738@gmail.com</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
```
---
## API Reference
<ComponentReference mainComponent="Table" componentsToShow={[
"Table",
"Table.Pagination"
]} />
---
## Examples
### Table with Pagination
<ComponentExample name="table-pagination" hideFeedback />
+61
View File
@@ -0,0 +1,61 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Tabs`,
}
# {metadata.title}
A component that displays tabbed content.
In this guide, you'll learn how to use the Tabs component.
<ComponentExample name="tabs-demo" />
## Usage
```tsx
import { Tabs } from "@medusajs/ui"
```
```tsx
<Tabs>
<Tabs.List>
<Tabs.Trigger value="1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="2">Tab 2</Tabs.Trigger>
<Tabs.Trigger value="3">Tab 3</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="1">Panel 1</Tabs.Content>
<Tabs.Content value="2">Panel 2</Tabs.Content>
<Tabs.Content value="3">Panel 3</Tabs.Content>
</Tabs>
```
---
## API Reference
<ComponentReference mainComponent="Tabs" />
---
## Examples
### Controlled Tabs
<ComponentExample name="tabs-controlled" />
### Tabs with a Disabled Tab
<ComponentExample name="tabs-disabled" />
### Tabs with Icons
<ComponentExample name="tabs-icons" />
### Vertical Tabs
The `orientation` prop doesn't change the layout of the tabs, but it allows you to navigate between the tabs using the up and down arrow keys. You'll need to manually style the tabs vertically.
<ComponentExample name="tabs-vertical" hideFeedback />
+50
View File
@@ -0,0 +1,50 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Text`,
}
# {metadata.title}
A component that displays text using the typography styles from Medusa's design system.
In this guide, you'll learn how to use the Text component.
<ComponentExample name="text-demo" />
## Usage
```tsx
import { Text } from "@medusajs/ui"
```
```tsx
<Text>Text</Text>
```
---
## API Reference
<ComponentReference mainComponent="Text" />
---
## Examples
### Text Sizes
<ComponentExample name="text-sizes" />
### Text Weights
<ComponentExample name="text-weights" />
### Text Fonts
<ComponentExample name="text-fonts" />
### Text Leading
<ComponentExample name="text-leading" hideFeedback />
@@ -0,0 +1,42 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Textarea`,
}
# {metadata.title}
A component that displays a textarea field using Medusa's design system.
In this guide, you'll learn how to use the Textarea component.
<ComponentExample name="textarea-demo" />
## Usage
```tsx
import { Textarea } from "@medusajs/ui"
```
```tsx
<Textarea />
```
---
## API Reference
<ComponentReference mainComponent="Textarea" />
---
## Examples
### Controlled Textarea
<ComponentExample name="textarea-controlled" />
### Disabled Textarea
<ComponentExample name="textarea-disabled" hideFeedback />
+119
View File
@@ -0,0 +1,119 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Toaster and Toast Messages`,
}
# {metadata.title}
A component and utility for displaying brief messages to users, typically used for notifications or alerts. Toast messages appear momentarily on top of the application UI.
You can display multiple toast messages at once, and they will be stacked neatly.
In this guide, you'll learn how to use the Toaster component.
<ComponentExample name="toaster-demo" />
## Usage
First, import the `toast` utility and `Toaster` component from `@medusajs/ui`:
```tsx
import { Toaster, toast } from "@medusajs/ui"
```
Then, add the `Toaster` component somewhere in your tree hierarchy. For example, in your main application layout:
```tsx highlights={[["6"]]}
export default function AppLayout({ children }) {
return (
<html>
<body>
{children}
<Toaster />
</body>
</html>
)
}
```
Finally, use the `toast` utility in your components to display a toast message:
```tsx highlights={[["5", "info", "Display an informational message"]]}
export default function MyComponent() {
return (
<Button
onClick={() =>
toast.info("Toast title", {
description: "Toast body",
})
}
>
Trigger
</Button>
)
}
```
---
## API Reference
### Toast Utility Functions
The `toast` utility has the following functions to display different variants of toast messages:
- `info`: Display a toast message with an informational style.
- `error`: Display a toast message with an error style.
- `success`: Display a toast message with a success style.
- `warning`: Display a toast message with a warning style.
- `loading`: Display a toast message with a loading style.
Each of these functions accept two parameters:
1. A string indicating the title of the toast.
2. An object of [Toast component props](#toast-props).
### Toast Props
<ComponentReference mainComponent="Toast" />
### Toaster Props
<ComponentReference mainComponent="Toaster" />
---
## Examples
### Toast Variants
<Note>
The following example assumes you already have the `Toaster` component in [your application's tree](#usage).
</Note>
<ComponentExample name="toaster-all-variants" />
### Dismissable Toast
<Note>
The following example assumes you already have the `Toaster` component in [your application's tree](#usage).
</Note>
<ComponentExample name="toaster-dismiss" />
### Toast with Action
<Note>
The following example assumes you already have the `Toaster` component in [your application's tree](#usage).
</Note>
<ComponentExample name="toaster-with-action" hideFeedback />
@@ -0,0 +1,59 @@
import { ComponentExample } from "@/components/ComponentExample"
import { ComponentReference } from "@/components/ComponentReference"
export const metadata = {
title: `Tooltip`,
}
# {metadata.title}
A component that displays a pop-up with additional information when hovering over or focusing on an element.
In this guide, you'll learn how to use the Tooltip component.
<ComponentExample name="tooltip-demo" />
## Usage
```tsx
import { Tooltip } from "@medusajs/ui"
```
```tsx
<Tooltip content="Tooltip content">Trigger</Tooltip>
```
---
## API Reference
<ComponentReference mainComponent="Tooltip" />
---
## Usage Outside Medusa Admin with TooltipProvider
If you're using the `Tooltip` component in a project other than the Medusa Admin, make sure to include the `TooltipProvider` somewhere up in your component tree:
```tsx
<TooltipProvider>
<Tooltip content="Tooltip content">Trigger</Tooltip>
</TooltipProvider>
```
### TooltipProvider Reference
<ComponentReference mainComponent="TooltipProvider" />
---
## Examples
### Changing Tooltip Side
<ComponentExample name="tooltip-sides" />
### Set Tooltip Max Width
<ComponentExample name="tooltip-maxwidth" />
Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

+49
View File
@@ -0,0 +1,49 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
html {
@apply antialiased;
text-rendering: optimizeLegibility;
}
body {
@apply overflow-x-hidden;
}
*::selection {
@apply bg-medusa-bg-highlight;
}
*:not(.code-block-elm) {
scrollbar-color: var(--docs-border-base) var(--docs-bg-base);
}
.code-block-elm {
scrollbar-color: var(--docs-contrast-border-base) transparent;
}
aside * {
scrollbar-color: var(--docs-border-base) var(--docs-bg-subtle);
}
body[data-modal="opened"] {
@apply !overflow-hidden;
}
.text-wrap {
text-wrap: wrap;
}
/* Hack to hide navbar / toc when some components like prompt are opened. */
body[data-scroll-locked] .z-20,
body[data-scroll-locked] .z-10 {
z-index: 0 !important;
}
}
.grecaptcha-badge {
visibility: hidden;
}
+59
View File
@@ -0,0 +1,59 @@
import { HookValues } from "@/components/HookValues"
import { ComponentReference } from "@/components/ComponentReference"
import { ComponentExample } from "@/components/ComponentExample"
export const metadata = {
title: `usePrompt`,
}
# {metadata.title}
This hook returns a function that prompts the user to confirm an action.
In this guide, you'll learn how to use the `usePrompt` hook.
<ComponentExample name="use-prompt-demo" />
## Usage
```tsx
import { usePrompt } from "@medusajs/ui"
```
```tsx
const dialog = usePrompt()
const actionFunction = async () => {
const confirmed = await dialog({
title: "Are you sure?",
description: "Please confirm this action",
})
}
```
---
## API Reference
### usePrompt Return Value
<HookValues hook="usePromptReturn" />
### Returned Dialog Parameters
The dialog function returned by `usePrompt` accepts an object having the following properties:
<ComponentReference mainComponent="RenderPrompt" />
### Dialog Return Value
The dialog function returns a Promise that resolves to a boolean indicating whether the user confirmed the action.
---
## Examples
### Prompt with Verification Text
<ComponentExample name="use-prompt-verification" hideFeedback />
@@ -0,0 +1,38 @@
import { HookValues } from "@/components/HookValues"
import { ComponentExample } from "@/components/ComponentExample"
export const metadata = {
title: `useToggleState`,
}
# {metadata.title}
This hook tracks a boolean value and toggles between its two states.
This guide explains how to use the `useToggleState` hook.
For example, you can use this hook to display a checkbox or a [Switch](../../components/switch/page.mdx) that toggles a [Focus Modal](../../components/focus-modal/page.mdx).
<ComponentExample name="use-toggle-state-demo" hideFeedback />
## Usage
```tsx
import { useToggleState } from "@medusajs/ui"
```
```tsx
const [state, open, close, toggle] = useToggleState()
```
---
## API Reference
### useToggleState Parameters
<HookValues hook="useToggleStateProps" />
### useToggleState Return Value
<HookValues hook="useToggleStateReturn" hideFeedback />
Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

+80
View File
@@ -0,0 +1,80 @@
import { IconSearch } from "@/components/IconSearch"
import { ComponentExample } from "@/components/ComponentExample"
import { Prerequisites } from "docs-ui"
export const metadata = {
title: `Icons`,
}
# {metadata.title}
In this guide, you'll learn how to install and use Medusa UI icons.
The Medusa UI icons package is a collection of React icon components from Medusa's design system. You can use these icons either in your Medusa Admin customizations, or in your standalone React projects.
## Installation
The Medusa UI icons package is available by default in your Medusa application, so you can use them in your Medusa Admin customizations without any additional installation steps.
### Installation in Standalone Projects
<Prerequisites
items={[
{
text: "React 16.8+ installed in your project.",
link: "https://react.dev/",
}
]}
/>
To install the Medusa UI icons package in your React-based project, run the following command:
```bash npm2yarn
npm install @medusajs/icons
```
---
## Usage
You can import and use the icons in your React components:
```tsx
import { Sun } from "@medusajs/icons"
export default function Component() {
return (
<Sun />
)
}
```
---
## Icons List
Below is a list of all the icons available in the Medusa UI design system. Click on any icon to copy its component name.
<IconSearch />
---
## Icon Props
Icons accept all props that an `svg` element accepts.
### Icon Color
By default, outline icons' stroke color and solid icon's fill color are set to `currentColor`.
You can set a different color by passing the `color` prop.
<ComponentExample name="icon-color" />
You can also use a CSS class by passing the `className` prop.
<ComponentExample name="icon-color-classes" />
### Icon Size
All icon's width and height are `20px` and it's not possible to change them.
@@ -0,0 +1,50 @@
export const metadata = {
title: `Install Medusa UI for Medusa Admin Customizations`,
}
# {metadata.title}
In this guide, you'll learn how to use Medusa UI for building Medusa Admin customizations.
## Use Medusa UI in Medusa Admin
The `@medusajs/ui` and `@medusajs/icons` packages are already installed as dependencies of the `@medusajs/admin-sdk` package in your Medusa project. They're installed by default in your Medusa plugins as well.
So, you can import the packages and use them in your Medusa Admin customizations without any additional installation steps.
For example, to use the UI and icon packages in a UI route:
```tsx title="src/admin/routes/custom/page.tsx"
import { defineRouteConfig } from "@medusajs/admin-sdk"
import { ChatBubbleLeftRight } from "@medusajs/icons"
import { Container, Heading } from "@medusajs/ui"
const CustomPage = () => {
return (
<Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4">
<Heading level="h2">This is my custom route</Heading>
</div>
</Container>
)
}
export const config = defineRouteConfig({
label: "Custom Route",
icon: ChatBubbleLeftRight,
})
export default CustomPage
```
In this example, you use the [Container](../../components/container/page.mdx) and [Heading](../../components/heading/page.mdx) components in the UI route. You also use the `ChatBubbleLeftRight` icon from the [Icons package](../../icons/overview/page.mdx) for the UI route's sidebar item.
---
## Related Resources
If you're building Medusa Admin customizations, check out the following documentation guides:
- [Admin Widgets](!docs!/learn/fundamentals/admin/widgets): Insert custom components into existing Medusa Admin pages.
- [Admin UI Routes](!docs!/learn/fundamentals/admin/ui-routes): Add new pages to the Medusa Admin.
- [Admin Components & Layouts](!resources!/admin-components): Use Medusa UI to implement common Medusa Admin components and layouts for a consistent design in your customizations.
@@ -0,0 +1,154 @@
import Feedback from "@/components/Feedback"
import { Note } from "docs-ui"
export const metadata = {
title: `Install Medusa UI in Standalone Projects`,
}
# {metadata.title}
In this guide, you'll learn how to install and use Medusa UI in a standalone project.
Medusa UI is a React UI library that, while intended for use within Medusa projects, can also be used in any React project.
<Note>
The icons package is installed independently from Medusa UI. Learn how to install it in the [Icons](../../icons/overview/page.mdx) guide.
</Note>
---
## Medusa UI Compatibility
To use Medusa UI in your standalone project, you must have:
- React 18+ installed. Most React-based frameworks and libraries, such as Next.js and Vite, are compatible with this requirement.
- [Tailwind CSS](https://v3.tailwindcss.com/) installed. The components in Medusa UI are styled using Tailwind CSS, so you'll need to install it in your project as well.
- Medusa UI was built with Tailwind CSS v3, but it may also support v4.
---
## Step 1: Install Medusa UI
In your standalone project, install the Medusa UI package with the following command:
```bash npm2yarn
npm install @medusajs/ui
```
---
## Step 2: Install UI Presets
Medusa UI customizes Tailwind CSS classes to implement its design system, so you must also install the Medusa UI preset package.
To install the Medusa UI preset, run the following command:
```bash npm2yarn
npm install @medusajs/ui-preset --save-dev
```
---
## Step 3: Configure Tailwind CSS
Next, you'll need to configure Tailwind CSS to use the Medusa UI preset and explicitly add the paths to the Medusa UI components as content files.
### Tailwind CSS v3 Configurations
In Tailwind CSS v3, which is the recommended version to use with Medusa UI, you need to add the following configurations to your `tailwind.config.js` or `tailwind.config.ts` file:
1. Add the Medusa UI preset to the `presets` array.
2. Ensure that the `content` field includes the path to the Medusa UI package.
```js title="tailwind.config.js" highlights={[["5"]]}
module.exports = {
presets: [require("@medusajs/ui-preset")],
content: [
// ...
"./node_modules/@medusajs/ui/dist/**/*.{js,jsx,ts,tsx}",
],
// ...
}
```
If your project is in a monorepo, you'll need to resolve the path to the `@medusajs/ui` package from the monorepo root:
export const monorepoHighlights = [
["3", "uiPath", "Resolve the UI package path from `node_modules`."],
["13"]
]
```tsx title="tailwind.config.js" highlights={monorepoHighlights}
const path = require("path")
const uiPath = path.resolve(
require.resolve("@medusajs/ui"),
"../..",
"\*_/_.{js,jsx,ts,tsx}"
)
module.exports = {
presets: [require("@medusajs/ui-preset")],
content: [
// ...
uiPath,
],
// ...
}
```
### Tailwind CSS v4 Configurations
Medusa UI isn't officially compatible with Tailwind CSS v4 yet, so use it with caution.
In your CSS file that imports Tailwind CSS, add the following `@import`, `@config`, and `@source` directives:
```css
@import "tailwindcss";
@source "../node_modules/@medusajs/ui";
@config "@medusajs/ui-preset";
```
This will explicitly include the Medusa UI preset and its components in your Tailwind CSS build and apply the preset styles to your project.
---
## Step 4: Use Medusa UI in Standalone Projects
You can now start building your application with Medusa UI.
For example, you can use the `Button` in your custom components:
```tsx
import { Button } from "@medusajs/ui"
export function ButtonDemo() {
return <Button>Button</Button>
}
```
Refer to the documentation of each component to learn about its props and usage.
<Feedback title={"Install in Standalone Project"} />
---
## Update UI Packages in Standalone Projects
Medusa's design system packages, including `@medusajs/ui` and `@medusajs/ui-preset`, are versioned independently from other `@medusajs/*` packages. However, they're still released as part of Medusa's releases.
So, to find the latest updates and breaking changes to any of these packages, refer to the [release notes in the Medusa GitHub repository](https://github.com/medusajs/medusa/releases).
To update these packages in your standalone project, update their version in your `package.json` file and re-install dependencies. For example:
```json title="package.json"
{
"dependencies": {
"@medusajs/ui": "4.0.0",
"@medusajs/ui-preset": "4.0.0"
}
}
```
+71
View File
@@ -0,0 +1,71 @@
import type { Metadata } from "next"
import { Inter, Roboto_Mono } from "next/font/google"
import Providers from "@/providers"
import "./globals.css"
import { BareboneLayout, TightLayout } from "docs-ui"
import { config } from "@/config"
import clsx from "clsx"
import Footer from "@/components/Footer"
const ogImage =
"https://res.cloudinary.com/dza7lstvk/image/upload/v1732200992/Medusa%20Resources/opengraph-image_daq6nx.jpg"
export const metadata: Metadata = {
title: {
template: `%s - ${config.titleSuffix}`,
default: config.titleSuffix || "",
},
description:
"Learn about Medusa UI, A React package with primitives for building Medusa applications.",
metadataBase: new URL(
process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
),
openGraph: {
images: [
{
url: ogImage,
type: "image/jpeg",
height: "1260",
width: "2400",
},
],
},
twitter: {
images: [
{
url: ogImage,
type: "image/jpeg",
height: "1260",
width: "2400",
},
],
},
}
export const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
weight: ["400", "500"],
})
export const robotoMono = Roboto_Mono({
subsets: ["latin"],
variable: "--font-roboto-mono",
})
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<BareboneLayout
htmlClassName={clsx(inter.variable, robotoMono.variable)}
gaId={process.env.NEXT_PUBLIC_GA_ID}
>
<TightLayout ProvidersComponent={Providers} footerComponent={<Footer />}>
{children}
</TightLayout>
</BareboneLayout>
)
}
@@ -0,0 +1,85 @@
import { getCleanMd } from "docs-utils"
import { existsSync } from "fs"
import { unstable_cache } from "next/cache"
import { notFound } from "next/navigation"
import { NextRequest, NextResponse } from "next/server"
import path from "path"
import { addUrlToRelativeLink } from "remark-rehype-plugins"
import type { Plugin } from "unified"
import * as Icons from "@medusajs/icons"
import * as HookValues from "@/specs/hook-values"
import { colors as allColors } from "@/config/colors"
type Params = {
params: Promise<{ slug: string[] }>
}
export async function GET(req: NextRequest, { params }: Params) {
const { slug = ["/"] } = await params
// keep this so that Vercel keeps the files in deployment
const basePath = path.join(process.cwd(), "app")
const componentSpecsPath = path.join(process.cwd(), "specs", "components")
const examplesPath = path.join(process.cwd(), "specs", "examples")
const filePath = path.join(basePath, ...slug, "page.mdx")
if (!existsSync(filePath)) {
return notFound()
}
const cleanMdContent = await getCleanMd_(
filePath,
{ examplesPath, specsPath: componentSpecsPath },
{
after: [
[addUrlToRelativeLink, { url: process.env.NEXT_PUBLIC_BASE_URL }],
] as unknown as Plugin[],
}
)
return new NextResponse(cleanMdContent, {
headers: {
"Content-Type": "text/markdown",
},
status: 200,
})
}
const getCleanMd_ = unstable_cache(
async (
filePath: string,
parserOptions: {
examplesPath: string
specsPath: string
},
plugins?: { before?: Plugin[]; after?: Plugin[] }
) => {
const iconNames = Object.keys(Icons).filter((name) => name !== "default")
return getCleanMd({
file: filePath,
plugins,
parserOptions: {
ComponentExample: {
examplesBasePath: parserOptions.examplesPath,
},
ComponentReference: {
specsPath: parserOptions.specsPath,
},
IconSearch: {
iconNames,
},
HookValues: {
hooksData: HookValues,
},
Colors: {
colors: allColors,
},
},
})
},
["clean-md"],
{
revalidate: 3600,
}
)
+47
View File
@@ -0,0 +1,47 @@
---
hide_content_menu: true
---
import { CardList, H1 } from "docs-ui"
import {
BookOpen,
AcademicCapSolid,
ComputerDesktopSolid,
BuildingStorefront
} from "@medusajs/icons"
export const metadata = {
title: `Page Not Found`,
}
# {metadata.title}
The page you were looking for isn't available.
If you think this is a mistake, please [report this issue on GitHub](https://github.com/medusajs/medusa/issues/new?assignees=&labels=type%3A+docs&template=docs.yml).
<CardList
itemsPerRow={2}
items={[
{
title: "Get Started Docs",
href: "/",
icon: BookOpen
},
{
title: "Commerce Modules",
href: "!resources!/commerce-modules",
icon: AcademicCapSolid
},
{
title: "Admin API reference",
href: "!api!/admin",
icon: ComputerDesktopSolid
},
{
title: "Store API reference",
href: "!api!/store",
icon: BuildingStorefront
}
]}
/>
+44
View File
@@ -0,0 +1,44 @@
import { FigmaCard } from "@/components/FigmaCard"
export const metadata = {
title: `Medusa UI Documentation`,
}
# {metadata.title}
Welcome to Medusa UI, a React implementation of the Medusa design system.
Medusa UI is a collection of components, hooks, utility functions, icons, and [Tailwind CSS](https://tailwindcss.com/) classes that can be used to build
a consistent user interface across the Medusa Admin and client applications.
<FigmaCard />
---
## Packages
Medusa UI is split into multiple packages. Each package is published to npm
and can be installed separately.
- `@medusajs/ui` - React components, hooks, and utility functions used
in Medusa UI.
- `@medusajs/ui-preset` - Tailwind CSS preset containing all the classes
used in Medusa UI.
- `@medusajs/icons` - Icons used in Medusa UI.
Learn how to install and use these packages either for [Medusa Admin](./installation/medusa-admin-extension/page.mdx) customizations or a [standalone project](./installation/standalone-project/page.mdx).
---
## How Medusa UI is Built
At its core, Medusa UI is a styled and slightly opinionated implementation of [Radix Primitives](https://www.radix-ui.com/primitives).
Our team has also referenced the fantastic [shadcn/ui](https://ui.shadcn.com/) for inspiration in certain implementations.
Our team strongly believes in keeping the components simple and
composable, much like Medusa's foundation. This allows you to build whatever you need.
Our team has tried to avoid overloading
the component API and, instead, has leveraged the native HTML API, which gets implemented
and respected accordingly, and passed to the underlying elements.
+13
View File
@@ -0,0 +1,13 @@
import { retrieveMdxPages } from "build-scripts"
import type { MetadataRoute } from "next"
import path from "path"
import { config } from "../config"
import { basePathUrl } from "../utils/base-path-url"
export default function sitemap(): MetadataRoute.Sitemap {
return retrieveMdxPages({
basePath: path.resolve("app"),
}).map((filePath) => ({
url: `${config.baseUrl}${basePathUrl(filePath)}`,
}))
}
+92
View File
@@ -0,0 +1,92 @@
export const metadata = {
title: `clx`,
}
# {metadata.title}
`clx` is a utility function that adds class names to your components, with support for conditional classes and merging Tailwind CSS classes.
In this guide, you'll learn how to use the `clx` utility function.
## Usage
The `clx` function is built using [clsx](https://www.npmjs.com/package/clsx) and [tw-merge](https://www.npmjs.com/package/tw-merge). It is intended to be used with [Tailwind CSS](https://tailwindcss.com/) to efficiently add classes to your components.
`clx` is useful for:
- Conditionally apply classes based on props or state. For example, you can apply the `hidden` class if a component's `open` state variable is `false`.
- Merge multiple strings into a single class name string. For example, you can apply class names to the component, and allow passing additional class names as props.
- Override conflicting Tailwind CSS classes. For example, if you specify a `p-2` class name on your component, and you pass a `p-4` class name as a prop, the `p-4` class will take precedence.
- The last class name specified will take precedence over any previous class names.
For example:
```tsx
import { clx } from "@medusajs/ui"
type BoxProps = {
className?: string
children: React.ReactNode
mt: "sm" | "md" | "lg"
}
const Box = ({ className, children, mt }: BoxProps) => {
return (
<div
className={clx(
"flex items-center justify-center",
{
"mt-4": mt === "sm",
"mt-8": mt === "md",
"mt-12": mt === "lg",
},
className
)}
>
{children}
</div>
)
}
```
In the above example, you use `clx` to:
- Apply a base style.
- Apply a margin top that depends on the `mt` prop.
- Add class names passed as a prop.
`clx` ensures that Tailwind CSS classes are merged without style conflicts.
---
## API Reference
### clx Parameters
`clx` accepts any number of arguments, each of them can be of the following types:
- `string`: A string of class names to apply.
```tsx
clx("flex items-center justify-between")
```
- `Record<string, boolean>`: An object whose keys are the class names to apply, and the values are booleans indicating whether to apply the class names.
```tsx
clx({
"flex items-center justify-between": isFlex,
})
```
- `Array`: An array of strings or objects to apply.
```tsx
clx([
"flex items-center justify-between",
{
"hidden": isHidden,
},
])