Conventions
What this repository expects from a change, and where its stated conventions differ from the current code.
Formatting
Prettier formats the code, configured in .prettierrc. It uses single quotes, semicolons, trailing commas,
120-character lines, and proseWrap: always, which hard-wraps Markdown.
@shopify/prettier-plugin-liquid formats Liquid.
A pre-commit hook runs Prettier over staged files. npm install installs the hook through simple-git-hooks, so a
fresh clone where nobody ran npm install has no hook.
.editorconfig and .vscode/settings.json turn on format on save. .vscode/extensions.json recommends the Shopify
Liquid extension, which shows Theme Check results inline.
TypeScript
strict, noEmit, isolatedModules and forceConsistentCasingInFileNames are all on. The target is ES2022, with
Bundler module resolution.
Import through the @/ alias instead of long relative paths. Both @/ and ~/ resolve to src/.
tsc only checks src/. It cannot read Liquid, so it cannot tell you that a value on window.theme is missing at
runtime. See Liquid to JavaScript contract.
Logging
Use createLogger('namespace') from src/lib/logger.ts instead of console. The logger prints nothing unless a
developer turns it on, so log calls left in the code do not reach shoppers.
import { createLogger } from '@/lib/logger';
const log = createLogger('my-feature');
log.info('mounted');Some older code still calls console directly. The logger patches the global console, so that output is hidden too. New
code should still use a namespace, so a developer can turn on its output without everything else.
Tag cart writes with their source
src/lib/cart-source.ts exports withCartSource, which adds a _source line item property in the form
<surface>:<function>. Shopify hides properties that start with an underscore on the storefront and at checkout. They
still appear in /cart.js, in the order admin and in webhooks.
Use it on every add to cart. The _source property is the only record of which code added a line, and with this many
apps writing to the cart, you will need that record.
Section schema requirements
Make merchant-facing behaviour configurable. Add an enable toggle and settings for wording, images and thresholds
instead of hardcoding them. AGENTS.md states this requirement, and reviewers check it first.
Run Theme Check after any schema change:
npm run lint:fix
npm run lintFour section schemas contain trailing commas. Shopify and Theme Check both accept them, but a strict JSON parser rejects
them. Do not add more, because any tool that reads schemas with a standard JSON parser fails on them. The four are
sections/medispa-service-callout.liquid, sections/review-carousel.liquid, sections/blog-posts-redesign.liquid and
sections/seo-content-redesign.liquid.
Section structure
The stated convention is two wrappers per section. The outer element carries the background so it can span the full
viewport width. The inner element limits the content width with calc(100% - var(--gutter)), where --gutter is a
schema setting.
The code does not match this yet. No section uses a --gutter custom property. A few sections use the wrapper pattern,
and they name the wrappers after the section instead of using a shared class:
<div class='shop-by-routine--inner-wrapper'>{ "class": "shop-by-routine--outer-wrapper" }Follow the convention for new sections, using the section-named form shown above, because the existing examples use it. Do not convert old sections as part of an unrelated change.
Naming
Liquid files use kebab case. A dot separates a family from its member, as in mini-cart.line-items.liquid. The fn.
prefix marks a snippet used for its return value.
TypeScript files use kebab case. React component files use PascalCase to match the component name.
Custom element tag names match their file names, so mini-cart-footer.ts defines <mini-cart-footer>.
Tailwind
Tailwind classes use the tw- prefix, and preflight is off, because Tailwind's reset would break the theme's own base
styles. important is on, so a tw- class overrides theme CSS.
The brand colours are ba-light-grey, ba-medium-grey, ba-dark-grey and ba-pink. The fonts are ba-title,
ba-body and ba-MinerveModern.
The content globs cover ./**/*.liquid and ./src/**/*.{js,ts,jsx,tsx}, so a class used only in Liquid still ends up
in the CSS. A class built at runtime from string fragments does not. If you need one, add it to safelist in
tailwind.config.cjs.
Git
Name branches after the issue they come from, for example 2-ba-115-fx-auhk-update-gift-cards-page---update.
Only the theme pull workflow writes to the production branch. Do not branch from it or open pull requests against it.
See Deploy and roll back.
What this repository does not have
The repository has no test suite, no CI that builds or type-checks a pull request, and no lint gate other than the local pre-commit hook.
Checking a change is therefore manual. Every operations page in these docs ends with a "Verify the change" section, and a pull request should say what you checked and on which preview theme.