Base Composition


Create a component by calling ma (or any name of your choice) with a tag name and a template literal string.

Example

react
import ma from "@marmo/react"
 
const Container = ma.div`
  py-2 px-5
  min-h-24
`

With Wrapper

react
import ma from "@marmo/react"
 
const Container = ma.div`
  py-2 px-5
  min-h-24
`
 
const MyPage = () => {
  return (
    <Container>
      <h1>Hello World</h1>
    </Container>
  )
}
 
export default MyPage

Result

output.html
<div class="py-2 px-5 min-h-24">
  <h1>Hello World</h1>
</div>

Pass and Receive properties

Prefix incoming props with `$`

Prefix styling props with a $ sign. This distinguishes props used by Marmo from props intended for the rendered element. This pattern should also avoid conflicts with reserved prop names.

Marmo filters $-prefixed props and props registered as variant keys. All other props are forwarded. Marmo does not perform runtime validation of HTML attributes.

TypeScript validates ordinary props against the selected intrinsic element when the types are known. That compile-time check does not imply runtime HTML-attribute validation: JavaScript callers, casts, and custom props can still reach the rendered element. Use $ props for styling-only values and data-* or aria-* attributes for intentional DOM metadata.

Pass props to the component and use them in the template literal string and in the component prop validation.

react - javascript
import ma from '@marmo/react'
 
const SomeButton = ma.button`
  text-lg
  mt-5
  ${({ $isActive }) => ($isActive ? 'bg-blue-400 text-white' : 'bg-blue-400 text-blue-200')}
  ${({ $isLoading }) => $isLoading && 'opacity-90 pointer-events-none'}
`
 
const MyComponent = () => {
  return (
    <SomeButton $isActive $isLoading>
      Click Me
    </SomeButton>
  )
}

Result

output.html
<button class="text-lg mt-5 bg-blue-400 text-white opacity-90 pointer-events-none">
  Click Me
</button>

Class merging

Marmo combines generated classes with classes supplied by the consumer using tailwind-merge. Consumer classes are later, so conflicting Tailwind utilities from the consumer win while non-conflicting generated classes remain.

react
const Panel = ma.div`rounded p-2 text-sm`
 
const Example = () => <Panel className="p-6">Content</Panel>
// rounded p-6 text-sm