Built for Light
Six rules that keep Light calm when a merchant installs ten modules.
Light stays simple only if the modules on it stay small. A merchant who installs ten modules should still find a calm admin: the same sections, few numbers, few settings. These six rules say when to add something and, more often, when not to. Getting started turns them into a checklist, and every recipe links the rule that applies.
1. Place, don't add
A screen goes under the section whose job it does: account requests under Customers, a returns list under Orders, a blog under Content. A new top-level nav item or a new Apps category needs a reason in your module's README, because every one of them pushes the merchant's daily work further apart. Labels are one to three words named after the job, never after the vendor: "Account requests", not "Disrex Registration".
<item name="label" xsi:type="string" translate="true">Account requests</item>
<item name="parent" xsi:type="string">customers</item>2. Use the smallest surface
- A Home to-do before a Home widget. A to-do shows only while there is work, and a widget renders nothing when it has nothing to say.
- A card comes after the core content of a page. More than four fields on a card is a sign that the rest belongs in the advanced view.
- A header action goes in More actions. Light puts every pool header action there for you.
- A counter before a banner. A banner is for something that stops the shop.
The pilot shows its work as a Home to-do that reads the nav counter, so the number is the same everywhere and nothing new is drawn:
<item name="badge" xsi:type="string">account_requests</item>3. Counts mean work
A count tells the merchant that something waits for them. So a counter returns null at 0, uses the tone attention by default, and uses critical only when something is broken or blocks a sale. Never count things that need no action, such as all customers or all products.
if ($count <= 0) {
return null;
}
return new Badge($count, 'attention', (string)($count === 1
? __('%1 account request to review', $count)
: __('%1 account requests to review', $count)));4. Simple mode shows everyday settings
A settings page in simple mode shows the few fields a merchant changes: named one by one, with a label and a note in plain words. Everything else stays in the stock section, behind the hint "Only available in the advanced view". There is no wildcard, so a new field in your system.xml never appears in simple mode by accident.
<item name="on" xsi:type="string">general/enabled</item>
<item name="replace" xsi:type="string">general/override_core_registration</item>5. Pins belong to the merchant
The merchant pins the apps they use every day. Apps and bridges don't set pinned_by_default: that key is for an agency that sets up one shop, in its own per-client module. The scaffold never writes it. Acme_LightProof sets it only to prove the mechanism works, and says so:
<!--
Proof of the mechanisms, not a pattern to copy: the top-level nav item, the "b2b" category and pinned_by_default
exist so a browser test can see each surface work from outside core. A real app goes under an existing section and
category, and leaves pins to the merchant (developer guide, ux-guidelines.mdx rules 1 and 5).
-->6. Warm copy
- English source in US English, and every label has
translate="true". Ship a CSV for each locale Light ships (en_GBwhere your British wording differs,nl_NL). Light's Dutch uses the informal "je", so a Dutch row that reuses Light's words matches it. - The badge vocabulary of the Design system: the same words and tones for the same states across Light.
- An action never reads like a status: "Mark handled" is an action, "Handled" is a status, and they get different Dutch words.
- An empty state says what will appear, not that something is missing: "When a business customer fills in the sign-up form, the request shows up here."
- Admin text is informal ("je", "du"). Customer text follows the store's setting (
FormOfAddressInterface::forStore()). Write your basenl_NL.csvin the informal form andde_DE.csvin the formal form, and ship the rows that change ini18n/nl_NL.formal.csvandi18n/de_DE.informal.csv: every customer row with a pronoun, and the Dutch greeting. When your customer mail shows a stock phrase with a pronoun, add its other form too. The storefront JS dictionary holds the base form only, and a theme's CSV wins over your variant rows (Channels and store views).
"Mark handled","Markeren als afgehandeld"A formal variant file holds only the customer rows that change with the form. Light's Orders module ships these:
"About your order #%1","Over uw bestelling #%1"
"Dear %name,","Beste %name,"
"Look up this number on the website of %carrier to follow your parcel.","Zoek dit nummer op de website van %carrier op om uw pakket te volgen."Last updated on