diff --git a/src/routes/reference/components/suspense.mdx b/src/routes/reference/components/suspense.mdx index 45a66d75a..89f0173a7 100644 --- a/src/routes/reference/components/suspense.mdx +++ b/src/routes/reference/components/suspense.mdx @@ -13,150 +13,78 @@ tags: - data-fetching version: '1.0' description: >- - Handle async operations elegantly in SolidJS with Suspense. Show loading - states while resources load without blocking UI rendering. + Coordinate loading states for async resources with a suspense boundary in Solid. --- -A component that tracks all resources read under it and shows a fallback placeholder state until they are resolved. What makes `Suspense` different than `Show` is that it is non-blocking in the sense that both branches exist at the same time even if not currently in the DOM. This means that the fallback can be rendered while the children are loading. This is useful for loading states and other asynchronous operations. +`Suspense` is the core boundary for async rendering in Solid. +Renders `fallback` content while tracked resources are pending. + +## Import ```tsx import { Suspense } from "solid-js" -import type { JSX } from "solid-js" - -function Suspense(props: { - fallback?: JSX.Element - children: JSX.Element -}): JSX.Element - ``` -Here's an example of a `Suspense` component that shows a loading spinner while the `User` component is loading. +## Type signature ```tsx -}> - - +import type { JSX } from "solid-js" +function Suspense(props: { + fallback?: JSX.Element; + children: JSX.Element; +}): JSX.Element; ``` -## Nested Suspense - -`` is triggered whenever a resource is read under the suspense boundary, and waits until all resources read -under the suspense boundary have resolved. Often, however, you may not want this behavior. For example, if your entire page is -wrapped in suspense, you may not want a resource that only populates a certain part of the page to trigger suspense. -In that case, you can wrap that resource usage in its own suspense boundary, and the resource will only trigger the -closest suspense boundary. - -For example, in the code below, only the `title()` resource will trigger the top level suspense boundary, and only the `data()` -resource will trigger the nested suspense boundary: - -```jsx -const MyComponent = () => { - const [title] = createResource(async () => { /* fetcher code here */ }) - const [data] = createResource(async () => { /* fetcher code here */ }) - -

{title()}

- - {data()} - -
-} +## Parameters -``` +### `fallback` -## The purpose of `` +- **Type:** `JSX.Element` +- **Required:** No -To understand the purpose of suspense, let's consider the following code snippets. These snippets will have some drawbacks which we will solve by using suspense. We will also see how it is possible to use `Suspense` yet not reap its benefits. +Content rendered while tracked resources are pending. -Our example use case is to display a user profile. A naive snippet would look like this: +### `children` -```jsx -const MyComponentWithOptionalChaining = () => { - const [profile] = createResource(async () => { - /* fetcher code here */ - }) - return ( - <> -
{profile()?.name}
-
{profile()?.email}
- - ) -} +- **Type:** `JSX.Element` +- **Required:** Yes -``` +Content rendered after tracked resources resolve. -In this code, `profile()` starts as `undefined`, and when the fetcher code finishes, resolves to an object with `name` and `email` properties. Although the resource has not resolved yet, the two `div`s are already created and attached to the document body, albeit with empty text nodes. Once the resource resolves, the `div`s are updated with the appropriate data. +## Return value -The downside of this approach is that the user is shown an empty component - let's see if we can do better than that in this next snippet: +- **Type:** `JSX.Element` -```jsx -const MyComponentWithShow = () => { - const [profile] = createResource(async () => { - /* fetcher code here */ - }) - return ( - fetching user data}> -
{profile().name}
-
{profile().email}
-
- ) -} +Returns a suspense boundary component that controls what renders to the DOM. +Component execution continues while the fallback is visible, preparing child content for display once resources resolve. -``` - -In this snippet, we first show a fallback when the resource hasn't resolved yet, and then switch to showing the profile data once it has. This results in a better user experience. +## Examples -On the other hand, there is a slight downside to this approach. In our first example (using optional chaining), the divs were created immediately, and once the resource resolves all that is needed to be done is to fill in the text of the `div`s. But in our second example (using ``), the `div`s are only created once the resource has resolved, which means there is more work that needs to be done after the resource has resolved before the data can be shown to the user (of course, in this toy example the amount of DOM work is relatively trivial). +### Basic usage -We can have the best of both worlds by using {""}: +Use a boundary whenever a subtree reads async resources and requires an explicit loading state. -```jsx -const MyComponentWithSuspense = () => { - const [profile] = createResource(async () => { - /* fetcher code here */ - }) - return ( - fetching user data}> -
{profile()?.name}
-
{profile()?.email}
-
- ) -} +```tsx +}> + + ``` -In this case, the `div`s are created immediately, but instead of being attached to the document body, the fallback is shown. Once the resource resolves, the text in the `div`s is updated, and then they are attached to the document (and the fallback removed). - -It is important to note that _the execution of the component does not pause_ when using suspense. Instead, when a resource is read under a suspense boundary, it ensures that the nodes are not attached to the document until after the resource has resolved. Suspense allows us to have the best of both worlds: do as much work as we can _before_ the resource resolves, and also show a fallback until then. - -With this in mind, we can understand that there isn't much gained from suspense in the following code: - -```jsx -const MyComponentWithSuspenseAndShow = () => { - const [profile] = createResource(async () => { - /* fetcher code here */ - }) - return ( - fetching user data}> - -
{profile().name}
-
{profile().email}
-
-
- ) -} -``` +### Nested boundaries + +Nested boundaries scope loading states to the nearest boundary, preventing one slow resource from blocking unrelated UI. -In this code, we don't create _any_ DOM nodes inside {""} before the resource resolves, so it is pretty much the same as the second example where we only used ``. -:::note - Suspense is triggered by reading a resource inside the {""}{" "} - boundary. Components wrapped with suspense still run fully, just as they would - without suspense. However, code wrapped in `onMount` and `createEffect` only - run after the resource resolves. -::: +```tsx +const [title] = createResource(fetchTitle) +const [data] = createResource(fetchData) -## Props +Loading title...

}> +

{title()}

+ Loading details...

}> +
+ + +``` -| Name | Type | Description | -| :--------- | :------------ | :--------------------------------------------------------------- | -| `fallback` | `JSX.Element` | The fallback component to render while the children are loading. | diff --git a/src/routes/solid-router/reference/components/a.mdx b/src/routes/solid-router/reference/components/a.mdx index 87f03d7b5..16085fa39 100644 --- a/src/routes/solid-router/reference/components/a.mdx +++ b/src/routes/solid-router/reference/components/a.mdx @@ -12,47 +12,118 @@ tags: - soft-navigation version: '1.0' description: >- - The A component provides enhanced anchor tags with automatic base path - support, active states, and soft navigation for better user experience. + Render router-aware links with active matching and client-side navigation. --- -Solid Router exposes the `` component as a wrapper around the [native anchor tag ](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a). -It relies on the routing context provided by the [`` component](/solid-router/reference/components/router) and if used outside, will triggers a runtime error.. +`A` renders an anchor element that integrates with Solid Router. +Requires routing context from [``](/solid-router/reference/components/router). -`` supports relative and base paths. `` doesn't. But `` gets augmented -when JS is present via a top-level listener to the DOM, so you get the -soft-navigation experience nonetheless. +## Import -The `` supports the [``](/solid-router/reference/components/router) base property (``) and prepend it to the received `href` automatically and the ``does not. -The same happens with relative paths passed to ``. +```tsx +import { A } from "@solidjs/router" +``` -The `` tag has an `active` class if its href matches the current location, and `inactive` otherwise. -By default matching includes locations that are descendants (e.g.: href `/users` matches locations `/users` and `/users/123`). +## Type signature -:::tip - Use the boolean `end` prop to prevent matching these. This is particularly - useful for links to the root route `/` which would match everything. -::: +```tsx +import type { JSX } from "solid-js" -## Soft Navigation +interface AnchorProps extends Omit, "state"> { + href: string; + replace?: boolean; + noScroll?: boolean; + state?: unknown; + inactiveClass?: string; + activeClass?: string; + end?: boolean; +} -When JavaScript is present at the runtime, both components behave in a very similar fashion. -This is because Solid Router adds a listener at the top level of the DOM and will augment the native `` tag to a more performant experience (with soft navigation). +function A(props: AnchorProps): JSX.Element +``` -:::note +## Parameters -To prevent, both `` and `` tags from soft navigating when JavaScript is present, pass a `target="_self"` attribute. +### `href` -::: +- **Type:** `string` +- **Required:** Yes -## Props Reference +Destination path resolved by the router, including base paths. -| prop | type | description | -| ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| href | string | The path of the route to navigate to. This will be resolved relative to the route that the link is in, but you can preface it with `/` to refer back to the root. | -| noScroll | boolean | If true, turn off the default behavior of scrolling to the top of the new page | -| replace | boolean | If true, don't add a new entry to the browser history. (By default, the new page will be added to the browser history, so pressing the back button will take you to the previous route.) | -| state | unknown | [Push this value](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) to the history stack when navigating | -| inactiveClass | string | The class to show when the link is inactive (when the current location doesn't match the link) | -| activeClass | string | The class to show when the link is active | -| end | boolean | If `true`, only considers the link to be active when the current location matches the `href` exactly; if `false`, check if the current location _starts with_ `href` | +### `replace` + +- **Type:** `boolean` +- **Required:** No + +Replaces the current history entry instead of pushing a new entry. + +### `noScroll` + +- **Type:** `boolean` +- **Required:** No + +Prevents scrolling to the top after navigation. + +### `state` + +- **Type:** `unknown` +- **Required:** No + +Value pushed to `history.state` for the navigation entry. + +### `inactiveClass` + +- **Type:** `string` +- **Required:** No + +Class applied when the current location does not match `href` (defaults to `"inactive"`). + +### `activeClass` + +- **Type:** `string` +- **Required:** No + +Class applied when the current location matches `href` (defaults to `"active"`). + +### `end` + +- **Type:** `boolean` +- **Required:** No + +Controls how strictly the link's `href` is matched against the current location. +When `true`, only exact matches are considered active. +When `false` (default), descendant paths are also matched (e.g., `/users` matches both `/users` and `/users/123`). + +## Return value + +- **Type:** `JSX.Element` + +Returns an anchor element with client-side navigation. +Sets `aria-current="page"` on exact pathname matches. + +## Examples + +### Basic link + +```tsx +Users +``` + +### Active matching with `end` + +```tsx + + Home + +``` + +### Link with router `base` + +```tsx + + Settings + +``` + +Use native `` when you need direct browser navigation without router matching behavior. diff --git a/templates/README.md b/templates/README.md new file mode 100644 index 000000000..4c0b63e52 --- /dev/null +++ b/templates/README.md @@ -0,0 +1,26 @@ +# Reference page templates + +Use these templates when rewriting or adding reference pages. +They are starter files, not strict copy-and-paste requirements. +Each page must still follow the correct archetype and the repo's writing rules. + +## Available templates + +- `function-api.mdx` +- `component-api.mdx` +- `jsx-attribute-syntax.mdx` +- `environment-rendering-utility.mdx` + +## How to use them + +- Pick the template that matches the page archetype in `REFERENCE_STANDARDIZATION_PHASE_1.md`. +- Replace placeholder text with the real API details. +- Remove any optional sections that do not apply. +- Keep one sentence per source line. +- Move displaced guide-style content to `CONTENT_RELOCATION_LOG.md`. + +## Notes + +- Do not force every page into the `function-api.mdx` layout. +- JSX attribute pages may use `## Behavior` because they document syntax semantics. +- Component pages should document individual fields under `## Parameters` instead of a generic `props` block. diff --git a/templates/component-api.mdx b/templates/component-api.mdx new file mode 100644 index 000000000..dcfbf8f2a --- /dev/null +++ b/templates/component-api.mdx @@ -0,0 +1,52 @@ +--- +title: Component name +description: One-sentence factual description of what this component does. +--- + +# `` + +Add one or two short sentences that define the component and when it renders or coordinates content. + +## Import + +```ts +import { ComponentName } from "solid-js"; +``` + +## Component signature + +```ts +function ComponentName(props: ComponentNameProps): JSX.Element; +``` + +## Parameters + +### `when` + +- **Type:** `T` +- **Required:** Yes + +Describe the field in one or two factual sentences. + +### `fallback` + +- **Type:** `JSX.Element` +- **Required:** No + +Describe when this field is used. + +## Examples + +### Basic usage + +```tsx +import { ComponentName } from "solid-js"; + +function Example() { + return ; +} +``` + +## Related + +- [`relatedApi`](/reference/path/to/related-api) diff --git a/templates/environment-rendering-utility.mdx b/templates/environment-rendering-utility.mdx new file mode 100644 index 000000000..d0b41190b --- /dev/null +++ b/templates/environment-rendering-utility.mdx @@ -0,0 +1,53 @@ +--- +title: API name +description: One-sentence factual description of what this rendering or environment-specific API does. +--- + +# API name + +Add one or two short sentences that define the API and its environment-specific role. + +## Import + +```ts +import { ApiName } from "solid-js/web"; +``` + +## Type signature + +```ts +type ApiName = unknown; +``` + +## Availability + +State where the API is available, such as client-only, server-only, or both. + +## Parameters + +### `firstParameter` + +- **Type:** `Type` +- **Default:** `undefined` + +Describe the parameter if the API accepts arguments. + +## Return value + +- **Type:** `ReturnType` + +Describe the return value if the API returns one. + +## Examples + +### Basic usage + +```tsx +import { ApiName } from "solid-js/web"; + +ApiName(); +``` + +## Related + +- [`relatedApi`](/reference/path/to/related-api) diff --git a/templates/function-api.mdx b/templates/function-api.mdx new file mode 100644 index 000000000..17e196cca --- /dev/null +++ b/templates/function-api.mdx @@ -0,0 +1,67 @@ +--- +title: API name +description: One-sentence factual description of what this API does. +--- + +# API name + +Add one or two short sentences that define the API and its role. + +## Import + +```ts +import { ApiName } from "solid-js"; +``` + +## Type signature + +```ts +type ApiName = unknown; +``` + +## Parameters + +### `firstParameter` + +- **Type:** `Type` +- **Default:** `undefined` + +State the parameter's purpose in one or two factual sentences. + +#### `nestedOption` + +- **Type:** `Type` +- **Default:** `undefined` + +Describe the nested option only if the parameter is an options object. + +### `secondParameter` + +- **Type:** `Type` +- **Default:** `undefined` + +Describe the parameter. + +## Return value + +- **Type:** `ReturnType` + +Describe what the API returns and name important parts when needed. + +## Examples + +### Basic usage + +```tsx +import { ApiName } from "solid-js"; + +function Example() { + const value = ApiName(); + + return
{String(value)}
; +} +``` + +## Related + +- [`relatedApi`](/reference/path/to/related-api) diff --git a/templates/jsx-attribute-syntax.mdx b/templates/jsx-attribute-syntax.mdx new file mode 100644 index 000000000..e36697cc9 --- /dev/null +++ b/templates/jsx-attribute-syntax.mdx @@ -0,0 +1,45 @@ +--- +title: Attribute name +description: One-sentence factual description of what this JSX attribute or syntax form does. +--- + +# `attributeName` + +Add one or two short sentences that define the syntax and where it applies. + +## Syntax + +```tsx +
+``` + +## Value + +- **Type:** `ValueType` + +Describe the accepted value shape and any important variants. + +## Behavior + +Describe how Solid interprets, compiles, or applies this syntax. +Keep this section factual and limited to semantics needed to use the feature correctly. + +## Constraints + +- Add ordering rules, spread limitations, SSR caveats, or DOM constraints only when needed. + +## Examples + +### Basic usage + +```tsx +function Example() { + let element!: HTMLDivElement; + + return
; +} +``` + +## Related + +- [`relatedApi`](/reference/path/to/related-api)