This template is currently in progress!
I'm building this Notion as a CMS portfolio + blog template in public.
Follow my daily updates on X
and Bluesky
.
a portfolio website with a blog, built using Next.js with Notion as the CMS
manage all your content (pages, blogs, metadata) directly from your Notion app.
Launching soon, you'll be able to buy this template and use it for your own portfolio & blog.
Interested in buying this template? Message me on
X
or Bluesky
.
Rich text
Text 
Bold, Italicize, Underline, Link, code
, break, s p a c i ng,
Color Text
Default, Gray, Brown, Orange, Yellow, Green, Blue, Purple, Pink, Red.
Background Text
Default, Gray, Brown, Orange, Yellow, Green, Blue, Purple, Pink, Red.
Text Links 
External Link
This link navigates to the Notion website
( These are standard external links added in Notion to point to websites outside your domain. On our website, they open in a new tab. )
Internal Site Link
This link navigates to the blog page
( These are internal links created in Notion to point to other pages within your website. They open in the same tab for faster navigation. To create an internal link in Notion, use a direct path like /blog
β donβt include the full domain. The path must match an existing page on your site for it to be recognized and rendered correctly. )
Color Link
Default, Gray, Brown, Orange, Yellow, Green, Blue, Purple, Pink, Red.
Background Link
Default, Gray, Brown, Orange, Yellow, Green, Blue, Purple, Pink, Red.
Underline 
Normal Underline
Underline
Color Underline
Default, Gray, Brown, Orange, Yellow, Green, Blue, Purple, Pink, Red.
( You can see here that the underline color is inherited from the text color. )
Background Underline
Default, Gray, Brown, Orange, Yellow, Green, Blue, Purple, Pink, Red.
Strikethrough 
Normal Strikethrough
Strikethrough
Color Strikethrough
Default, Gray, Brown, Orange, Yellow, Green, Blue, Purple, Pink, Red.
( You can see here that the Strikethrough color is inherited from the text color. )
Background Strikethrough
Default, Gray, Brown, Orange, Yellow, Green, Blue, Purple, Pink, Red.
Inline Code
Default inline Code
inline code
Color text inline Code
Default
, Gray
, Brown
, Orange
, Yellow
, Green
, Blue
, Purple
, Pink
, Red
.
Background inline Code
Default
, Gray
, Brown
, Orange
, Yellow
, Green
, Blue
, Purple
, Pink
, Red
.
Different Backgrounds Code side by side
Yellow
Green
Blue
Default
Gray
Brown
Orange
Yellow
Green
Blue
Purple
Pink
Red
.
Different Text Colors inline inline Code side by side
Yellow
Green
Blue
Default
Gray
Brown
Orange
Yellow
Green
Blue
Purple
Pink
Red
inline code with Bold
Bold
inline code with Italicize
Italicize
inline code with Underline
Default
, Gray
, Brown
, Orange
, Yellow
, Green
, Blue
, Purple
,Pink
, Red
inline code with Strike Through
Default
, Gray
, Brown
, Orange
, Yellow
, Green
, Blue
, Purple
,Pink
, Red
inline code with Link inside
inline code with Emoji inside
const status = "
Success";
console.log("
Debug mode enabled");
const emoji = "
+
=
";
mix inline code with all annotations
Text inline Equation
Emojis in Text
All emojis in text are rendered as Twemojis for consistent appearance across devices.
People with Skin Tone Variations
Gendered Professions
Β // Developer
Β // Astronaut
Β // Artist
Popular and Expressive
Aesthetic Emojis for UI
People with Skin Tone Variations
Rich Text Rendering β How It Works
All text customizations are rendered with semantic HTML in mind. The structure is intentionally minimal, no unnecessary <span>
or <div>
clutter. Links are rendered using the <a>
tag, and code snippets use the <code>
tag for proper semantics and accessibility.
(Everything is styled to closely match the look and feel of a Notion page.)
External Links
External links are rendered using the <a>
tag with target="_blank"
and rel="noopener noreferrer"
attributes.
This ensures secure navigation by opening the link in a new tab without allowing the new page to access or control your original site, protecting it from potential security risks like tab-napping.
Internal Links
Internal links are rendered using Next.jsβs Link
component. This enables fast, client-side navigation with performance benefits, when you hover over these links, Next.js begins preloading the destination page in the background.
Inline equation
You can add inline equations in Notion using LaTeX syntax β and we support this feature as well.
Inline equations are rendered using KaTeX, just like in Notion, for fast and accurate math rendering directly inside text.
Twemoji
You may notice that these emojis look slightly different from the default system emojis.
Thatβs because we convert them into Twemojis, the open-source emoji set from π (formerly Twitter), designed for consistency across platforms.
We achieve this by parsing and replacing native emojis using the twemoji-parser package.
This makes the emoji rendering uniform across all browsers and devices, matching Notionβs emoji styling more closely.
Rich Text Support
Rich text styling is supported anywhere text appears, inside paragraph blocks, headings, list items, callouts, block captions, and all notion blocks.
This includes bold, italic, code, links, text color, and background color.
Rich Text Styling Behavior
In Notion, you can apply both a color and a background to rich text, but the Notion API only returns one at a time, either a color or a background. So, in this template, we replicate that limitation and render only one.
Some Notion blocks (like paragraphs, headings, callouts, etc.) also allow applying a text color or background color to the entire block. Just like with rich text, we apply only one style to the block, either color or background.
You can still customize individual text inside the block with its own color or background, separate from the blockβs styling.
This means a block can have a background, and specific words inside it can have their own rich text styling, just like in Notion.
Basic Blocks
Paragraph Block
Color Paragraph block
default color
gray color
brown color
orange color
yellow color
green color
blue color
purple color
pink color
red color
Background Paragraph block
default background
gray background
brown background
orange background
yellow background
green background
blue background
purple background
red background
pink background
Paragraph block with all text customizations
Lorem ipsum dolor sit, Emojis
Φ΄ΦΆΦΈβΎβ‘
using https://github.com/jdecked/twemoji-parser
, Bold, Italicize, Underline, My Portfolio link,
Code
, Break, S p a c i n g. Equations: blue color blue background Link site page referring link Β World Emoji Day
Β World Emoji Day
yooo hie lal a alsd v asdh
code1
code2
yo
Paragraph Block β How It Works
The text (paragraph) block is rendered using the <p>
HTML tag.
You can apply either a text color or a background color to the entire block.
In Notion, paragraph blocks do not support nested blocks, so this behavior is replicated here as well.
If a paragraph block is empty in your Notion page, we still render it.
This allows you to intentionally create spacing between blocks, just like you can in Notion.
Heading Blocks
Heading 1
Heading 2
Heading 3
Color Heading 1/2/3 block
Heading 1 block with color blue color blue background
You can see above even if a block has a background or color, any text inside it that has its own background or color still shows up just like in Notion. This works thanks to the RichText component.
Heading 2 block with color
Heading 3 block with color
(like paragraph you can give all colors to any heading 1/2/3 blocks)
Background Heading 1/2/3 block
Heading 1 block with background blue color blue background
Heading 2 block with background
Heading 3 block with background
(like paragraph you can give all colors to any heading 1/2/3 blocks)
Heading blocks with all text customizations
Heading 1 , Italicize, Underline, Link, code
, break, s p a c i ng, code1
code2
blue color blue background
Heading 2 , Italicize, Underline, Link, code
, break, s p a c i ng, code1
code2
blue color blue background
Heading 3 , Italicize, Underline, Link, code
, break, s p a c i ng, code1
code2
blue color blue background
Heading Blocks β How It Works
Heading blocks (1, 2, and 3) are rendered using the <h2>
, <h3>
, and <h4>
HTML tags.
We skip <h1>
for Heading 1 because <h1>
is reserved for the page title, maintaining proper document structure and SEO best practices.
You can apply either a text color or a background color to the entire heading block.
If a heading block is empty in your Notion page (i.e., contains no text), we do not render it.
In Notion, if you insert another block inside a heading block (making it a nested), Notion automatically converts it into a heading toggle block.
We support this behavior as well.
Bulleted list Block
Background Bulleted list block
- default color
- gray color
- brown color
- orange color
- yellow color
- green color
- blue color
- purple color
- pink color
- red color
Background Bulleted list block
- default background
- gray background
- brown background
- orange background
- yellow background
- green background
- blue background
- purple background
- pink background
- red background
Normal bulleted list example
- Boil fresh water
- Add coffee grounds to your filter or French press
- Pour hot water over the coffee
- Let it brew (about 4 minutes for French press)
- Press or filter the coffee
- Pour into your favorite mug
- Add milk or sugar if desired
- Enjoy your coffee break!
Bulleted List Block β How It Works
Each bulleted list item is rendered using the <li>
HTML tag.
Weβve added a custom feature where adjacent bulleted list items are grouped and wrapped inside a <ul>
element for proper HTML semantics.
By default, the Notion API does not return list items as grouped blocks, so we manually detect and group them to maintain structure.
You can apply either a text color or a background color to the entire bulleted list block.
In Notion, you can nest any block inside a list item β we replicate this behavior exactly.
As you nest bulleted list blocks inside one another, the bullet point style automatically adjusts based on the nesting level.
In Notion, the bullets cycle through disc
, circle
, and square
depending on the depth β we replicate this behavior as well.
If a Bulleted List block is empty in your Notion page (i.e., contains no text), we do not render it.
Numbered list Block
Background Numbered list block
- 1.default color
- 2.gray color
- 3.brown color
- 1.orange color
- 2.yellow color
- 3.green color
- 1.blue color
- 2.purple color
- 3.pink color
- 4.red color
Background Numbered list block
- 1.default background
- 2.gray background
- 1.brown background
- 2.orange background
- 1.yellow background
- 2.green background
- 3.blue background
- 1.purple background
- 2.pink background
- 4.red background
Normal Numbered list example
- 1.Boil fresh water
- 2.Add coffee grounds to your filter or French press
- 3.Pour hot water over the coffee
- 4.Let it brew (about 4 minutes for French press)
- 5.Press or filter the coffee
- 6.Pour into your favorite mug
- 7.Add milk or sugar if desired
- 8.Enjoy your coffee break!
Numbered List Block β How It Works
Each numbered list item is rendered using the <li>
HTML tag.
Weβve added a custom feature where adjacent numbered list items are grouped and wrapped inside an <ol>
element for proper HTML semantics.
By default, the Notion API does not return list items as grouped blocks, so we manually detect and group them to preserve the correct structure.
You can apply either a text color or a background color to the entire numbered list block.
In Notion, you can nest any block inside a list item β we replicate this behavior as well.
As you nest numbered list blocks inside one another, the numbering style automatically adjusts based on the nesting level.
In Notion, the styles cycle through numbers
, letters
, and Roman numerals
, depending on the depth β we replicate this behavior too.
If a Numbered List block is empty in your Notion page (i.e., contains no text), we do not render it.
To-do Block
To-do item (unchecked)
To-do item (checked)
color to do (checked todo text will not have block color but you can add text color by selecting individual text like this also strike through color can be change like this)
background to do (checked)
unchecked
color to do (unchecked)
background to do (unchecked) (showing nested blocks)
This is a paragraph inside an unchecked to-do.
- Bulleted list item
- Hi
- 1.Numbered item
- 2.Hi
Color To-do block
default color
gray color
brown color
orange color
yellow color
green color
blue color
purple color
pink color
red color
Background To-do block
default background
gray background
brown background
orange background
yellow background
green background
blue background
purple background
red background
pink background
To-do block with all text customizations
Lorem ipsum dolor sit, Emojis
Φ΄ΦΆΦΈβΎβ‘
using https://github.com/jdecked/twemoji-parser
, Bold, Italicize, Underline, My Portfolio link,
Code
, Break, S p a c i n g. Equations: blue color blue background Link site page referring link Β World Emoji Day
Β World Emoji Day
yooo hie lal a alsd v asdh
code1
code2
yo
To-do Block β How It Works
The To-do block is rendered using an <input type="checkbox">
along with a <p>
tag for the text content.
We include a semantic checkbox input for accessibility, marked as readOnly
and visually hidden to match Notionβs behavior.
In Notion, the To-do block does not use a standard HTML checkbox. Instead, it renders the checked and unchecked states using custom SVG icons β we replicate this behavior for a exact look.
You can apply either a text color or a background color to the entire block.
Just like in Notion, you can nest any block inside a To-do block, and we also able to render that as well.
If a To-do block is empty in your Notion page (i.e., it contains no text), we do not render it.
Toggle Block
Toggle block
hi share this template
Toggle block with no nested blocks ( Appears with a faded toggle icon )
Toggle Block with Background
If a background is applied to the toggle block, all nested blocks will inherit that background, unless a specific background is set on a nested block or rich text.
Toggle Block with Color
Similarly, if a color is applied to the toggle block, all nested content will inherit that color β unless a nested block or text span has its own color applied.
Color Toggle block
default color
gray color
brown color
orange color
yellow color
green color
blue color
purple color
pink color
red color
Background Toggle block
default background
hi
gray background
brown background
orange background
yellow background
green background
blue background
purple background
red background
pink background
Toggle Block β How It Works
The Toggle block is rendered using the native <details>
and <summary>
HTML tags, along with a <p>
tag for the toggle text β providing clean and semantic HTML.
In Notion, a Toggle block behaves similarly to a paragraph block, but it allows nesting any other Notion block inside it.
By default, nested blocks are collapsed and hidden. In Notion, you expand them by clicking the small triangle icon on the right.
We replicate this behavior, but with an improvement β the entire toggle block is clickable, not just the icon. Clicking anywhere on the toggle block will open or close it, and the whole block uses a pointer cursor to indicate interactivity.
If a Toggle block is empty in your Notion page (i.e., it contains no text), we do not render it β even if it has nested blocks inside.
Page Block
not supported
Callout Block
Color Callout block
Default text
Gray text
Brown text
Orange text
Yellow text
Green text
Blue text
Purple text
Pink text
Red Text
Background Callout block
Default
Gray
Brown
Orange
Yellow
Green
Blue
Purple
Pink
Red
Callout Block without Icon
Callout Block with nested blocks including callout text
Callout
Heading 1
Heading 2
Heading 3
paragraph
Callout Block with only nested blocks
Heading 1
Heading 2
Heading 3
paragraph
Callout block in callout block
Callout Block with all icons types
Twemoji (Standard Emojis)
Notion Icons, selected from Notionβs built-in icon library.

Custom Emojis, These are icons uploaded as custom emojis in Notion.

Uploaded File Icons, directly uploaded in Notion (e.g., PNG, JPG, SVG)
External URL Icons, sourced from an external URL, such as CDNs, public asset servers, or icon libraries like SVGRepo.
Callout Block β How It Works
The Callout block is rendered using the <figure>
HTML tag, along with a <p>
tag for the callout text β providing clean and semantic HTML.
In Notion, we can nest any block inside a Callout β either along with callout text, or with callout text with nested block, or as a callout with only nested blocks no callout text.
(Note: when it's a callout with only nested blocks, Heading 1, 2, and 3 do not have top margin in Notion.)
We have replicated this exact behavior and rendered it accordingly.
You can apply either a text color or a background color to the entire block.
In dark mode, Notion uses different callout background shades compared to standard blocks β weβve replicated this styling as well.
Callouts support various types of icons:
- You can use a standard emoji, a built-in Notion icon, a custom emoji, or even a directly uploaded file.
- You can also remove the icon entirely and display a plain callout β just like in Notion.
Notionβs built-in icon library displays different icons in light and dark modes, and weβve mirrored that behavior to ensure visual consistency.
Weβve also implemented a feature that handles custom emoji and uploaded file icons with local caching:
- Since these icons have expiring URLs (valid for only ~1 hour),
- We detect and download them locally to your Next.js project's
public/icons/custom_emoji
orpublic/icons/file
folders, - This ensures your callout icons render reliably on your site.
If a Callout block is empty, we still render it, just like Notion β this can be useful for spacing, layout, or visual dividers.
Quote Block
Color Quote block
default color
gray color
brown color
orange color
yellow color
green color
blue color
purple color
pink color
red color
Background Quote block
default background
gray background
brown background
orange background
yellow background
green background
blue background
purple background
red background
pink background
Quote Block with nested blocks
To be or not to be, that is the question.
β William Shakespeare
Quote with nested blocks
Heading 1 inside Quote
Some supporting paragraph text.
A bullet list item Another oneEven a nested quote block!
Quote Text Color
Stay hungry, stay foolish.
(The left border color of the quote block inherits from the blockβs text color.)
Quote Block β How It Works
The quote block is rendered using the <blockquote>
HTML tag, along with a <p>
tag for the quote text β providing clean and semantic HTML.
In Notion, you can nest any block inside a quote block, and we replicate this behavior exactly.
You can apply either a text color or a background color to the entire block.
If a quote block is empty (i.e., has no text), we do not render it β even if it contains nested blocks.
Table Block
Table block with Heading Row
Name | Role | |
---|---|---|
Alice | Developer | |
Bob | Designer | |
Table block with Heading Column
Task | Status |
---|---|
Create a website | In Progress |
Add features | Completed |
Table block with Both Headings
Category | Feature | Details |
---|---|---|
Performance | Fast Build Times | Built with Next.js 15, Turbopack, and Tailwind CSS for an optimized and beautiful UI. |
Design | Custom Templates | Beautiful and responsive |
Table block Without Heading Row or Heading Column
Cell | Cell | Cell | Cell |
Cell | Cell | Cell | Cell |
Cell | Cell | Cell | Cell |
Cell | Cell | Cell | Cell |
Large overflow Table block
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | Column 7 | Column 8 |
Row 1, Cell 1 | Row 1, Cell 2 | Row 1, Cell 3 | Row 1, Cell 4 | Row 1, Cell 5 | Row 1, Cell 6 | Row 1, Cell 7 | Row 1, Cell 8 |
Row 2, Cell 1 | Row 2, Cell 2 | Row 2, Cell 3 | Row 2, Cell 4 | Row 2, Cell 5 | Row 2, Cell 6 | Row 2, Cell 7 | Row 2, Cell 8 |
Row 3, Cell 1 | Row 3, Cell 2 | Row 3, Cell 3 | Row 3, Cell 4 | Row 3, Cell 5 | Row 3, Cell 6 | Row 3, Cell 7 | Row 3, Cell 8 |
Row 4, Cell 1 | Row 4, Cell 2 | Row 4, Cell 3 | Row 4, Cell 4 | Row 4, Cell 5 | Row 4, Cell 6 | Row 4, Cell 7 | Row 4, Cell 8 |
Row 5, Cell 1 | Row 5, Cell 2 | Row 5, Cell 3 | Row 5, Cell 4 | Row 5, Cell 5 | Row 5, Cell 6 | Row 5, Cell 7 | Row 5, Cell 8 |
Row 6, Cell 1 | Row 6, Cell 2 | Row 6, Cell 3 | Row 6, Cell 4 | Row 6, Cell 5 | Row 6, Cell 6 | Row 6, Cell 7 | Row 6, Cell 8 |
Row 7, Cell 1 | Row 7, Cell 2 | Row 7, Cell 3 | Row 7, Cell 4 | Row 7, Cell 5 | Row 7, Cell 6 | Row 7, Cell 7 | Row 7, Cell 8 |
Row 8, Cell 1 | Row 8, Cell 2 | Row 8, Cell 3 | Row 8, Cell 4 | Row 8, Cell 5 | Row 8, Cell 6 | Row 8, Cell 7 | Row 8, Cell 8 |
Row 9, Cell 1 | Row 9, Cell 2 | Row 9, Cell 3 | Row 9, Cell 4 | Row 9, Cell 5 | Row 9, Cell 6 | Row 9, Cell 7 | Row 9, Cell 8 |
Row 10, Cell 1 | Row 10, Cell 2 | Row 10, Cell 3 | Row 10, Cell 4 | Row 10, Cell 5 | Row 10, Cell 6 | Row 10, Cell 7 | Row 10, Cell 8 |
Table Blocks in Column blocks
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | Column 7 | Column 8 |
Row 1, Cell 1 | Row 1, Cell 2 | Row 1, Cell 3 | Row 1, Cell 4 | Row 1, Cell 5 | Row 1, Cell 6 | Row 1, Cell 7 | Row 1, Cell 8 |
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | Column 7 | Column 8 |
Row 1, Cell 1 | Row 1, Cell 2 | Row 1, Cell 3 | Row 1, Cell 4 | Row 1, Cell 5 | Row 1, Cell 6 | Row 1, Cell 7 | Row 1, Cell 8 |
Divider block
Link to page Block
work in progress
Media Blocks
Image Block
Uploaded File Images via Notion

Unsplash Notion image URL
Cloudinary image URL

Pexels image URL


Giphy image URL




Video Block
work in progress
Audio Block
Code Block
Code block with with notion rich text
JavaScript code block
function debounce(func, delay) { let timer; return function (...args) { clearTimeout(timer); timer = setTimeout(() => func.apply(this, args), delay); }; }
// Example usage:
const fetchData = () => { console.log("Fetching data..."); };
const debouncedFetch = debounce(fetchData, 1000);
document.getElementById("search").addEventListener("input", debouncedFetch);
File Block
Figma Keyboard Shortcuts for Windows.pdf
1636 KBdummy.pdf
Handling Notion-hosted and External Files in File & Audio Blocks
In both the File and Audio blocks, we receive either Notion-hosted URLs (files uploaded directly to Notion) or externally hosted URLs (e.g., S3, Dropbox, or public CDN links).
Now, Notion-hosted URLs are temporary, they typically expire after 1 hour. This means if we directly use these URLs in our custom Notion block renderer, the file or audio will stop working shortly after being loaded.
To address this, I implemented a workaround:
- For Notion-hosted audio block files, we download them during build time and store them in
/public/audio/
. - For Notion-hosted file block files, we store them in
/public/file/
. - For audio files, we extract the exact filename and format from the Notion URL and save it accordingly.
- For file blocks, we use the filename provided in the Notion API (
block.file.name
) and preserve it when saving.
Iβve also added a check to avoid redundant downloads, if a file already exists in the respective folder, we reuse it instead of downloading it again.
Although this approach increases the projectβs build size, it ensures long-term availability of files without relying on expiring Notion URLs.
I'm also considering uploading these Notion-hosted files to a CDN or cloud storage instead of storing them in the Next.js
public
folder, to reduce the overall project size.
Web Bookmark Block
A tool that connects everyday work into one space. It gives you and your teams AI toolsβsearch, writing, note-takingβinside an all-in-one, flexible workspace.


Next.js by Vercel is the full-stack React framework for the web.

Tailwind CSS is a utility-first CSS framework for rapidly building modern websites without ever leaving your HTML.


Extension for Visual Studio Code - Spelling checker for source code
Extension for Visual Studio Code - Code formatter using prettier
Schema.org is a set of extensible schemas that enables webmasters to embed structured data on their web pages for use by search engines and other applications.
A set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code.

react.gg is an interactive, challenge-based learning experience that will get you shipping modern React apps like a pro. Get 30% off during their launch saleβ¦


Advanced Blocks
Table of contents Block
Block equation
work in progress
Button
not supported
Breadcrumb
work in progress
Synced block
this block is synced from blog page
Blog Home Page
Heading 1
Heading 2
Heading 3
Toggle heading 1
Share this project with people who love Notion.
Toggle heading 2
Hi
Toggle heading 3
Share this project with people who love Notion.
Paragraph
- Bulleted list item
- one
- two
- 1.Numbered list item
- 2.one
- 3.two
Toggle heading 1
Share this project with people who love Notion.
Toggle heading 2
Hi
Toggle heading 3
Share this project with people who love Notion.
Columns Block
2 Columns
Column 1
Column 2
3 Columns with Custom Widths
Column 1
Column 2
Column 3
4 Columns
Column 1
Column 2
Column 3
Column 4
5 Columns
Column 1
Column 2
Column 3
Column 4
Column 5
Nested columns? Yes! You can even place a Columns block inside a column β just like Notion allows.
Column 1
Column 1
Column 2
Column 2
Supports all column layouts: 1, 2, 3, 4, and 5 columns.
This block in Notion is used to organize content side by side, perfect for layouts that need structure and flexibility.
It also accurately reflects custom column widths if you change a columnβs width in Notion, it will render with the exact same width here.
Big thanks to the Notion API for providing detailed column width data
Code - Mermaid
%% A simple Mermaid diagram
graph TD;
A[Hello, World!] --> B{Sum};
B -->|5| C[5];
B -->|10| D[10];
C --> E[Result];
D --> E;
flowchart LR
id1>This is the text in the box]
erDiagram
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
CUSTOMER ||--o{ ORDER : places
CUSTOMER ||--o{ INVOICE : "liable for"
DELIVERY-ADDRESS ||--o{ ORDER : receives
INVOICE ||--|{ ORDER : covers
ORDER ||--|{ ORDER-ITEM : includes
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
PRODUCT ||--o{ ORDER-ITEM : "ordered in"