# Getting started · Introduction Subtle highlights for your UI, with your existing colors, layout and interactions. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/ ## A little more alive. Group elements under one shared light and choose which surfaces respond. Give an area its own light when it should react independently. ## Start using Edge Start with [Installation](https://edge.bolerish.com/docs/installation/), learn the concepts in [Usage](https://edge.bolerish.com/docs/usage/), then follow [React](https://edge.bolerish.com/docs/react/usage/). Find settings in the [API reference](https://edge.bolerish.com/docs/react/api/). --- # Getting started · Installation Install Edge and start using it in React. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/installation/ ## Installation The React adapter requires React 18 or 19. Other framework adapters are not available yet. npm ```bash npm install @bolerish/edge ``` pnpm ```bash pnpm add @bolerish/edge ``` Yarn ```bash yarn add @bolerish/edge ``` Bun ```bash bun add @bolerish/edge ``` ## Default styles React prepares the default CSS automatically when a surface connects, with or without Edge.Provider. No stylesheet import is required. For SSR, render Edge.Styles once per document before application styles. If CSP requires a nonce, pass the same request nonce on the server and during hydration. ```tsx ``` ```css @import "@bolerish/edge/style.css"; ``` Existing CSS imports remain supported. The CSS file is also available for framework-independent use. When loading it explicitly, put it before application and utility styles; a reset may load first. Package CSS imports require a build tool that resolves package paths. ## Start using Edge Choose an area and its surfaces in [Usage](https://edge.bolerish.com/docs/usage/), then connect them with [React](https://edge.bolerish.com/docs/react/usage/). --- # Getting started · Usage Understand lights and surfaces before connecting your components. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/usage/ ## Choose an area A light controls a group of surfaces that respond together. Choose a section or a few elements to share one light. A surface is an element connected to that light. Only connected surfaces respond. Use a separate light for an independent area. ## Keep your UI Edge keeps your background, text, spacing and base border. Its highlight uses each surface’s own text color and border radius by default. Keep existing interactions and keyboard focus indicators. Choose the surface response in [Style](https://edge.bolerish.com/docs/styles/) and how the light moves in [Motion](https://edge.bolerish.com/docs/motion/). For input wrappers and decoration conflicts, see [Integration considerations](https://edge.bolerish.com/docs/integration/#wrap-inputs-you-own). For application-controlled position changes, see [layout changes](https://edge.bolerish.com/docs/integration/#refresh-after-layout-changes). ## Choose your framework Follow the guide for your framework. [ ### React ](https://edge.bolerish.com/docs/react/usage/) --- # React · Usage Start with Edge.Provider and Edge.Surface. Use useSurface to connect an existing component directly. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/react/usage/ ## Connect an area Complete [Installation](https://edge.bolerish.com/docs/installation/) first. In Server Component frameworks, use Edge from a client module marked with `"use client"`. Wrap the area in `Edge.Provider` and mark each responding element with `Edge.Surface`. The two cards below share one light; nested providers create independent lights. One light, your components ```tsx Example card Another example card ``` ## Keep your styles and events Use `as` to choose the HTML element. Native attributes, events and refs follow that element. Optional `className` and `style` props apply your styles. The provider adds no DOM; each surface renders one element. ```tsx Example button ``` Inputs need a wrapper. If an existing decoration conflicts, see [Integration considerations](https://edge.bolerish.com/docs/integration/). Choose appearance and movement in [Style](https://edge.bolerish.com/docs/styles/) and [Motion](https://edge.bolerish.com/docs/motion/). ## Connect an existing component If a Card or Button already renders its own HTML element, call [useSurface(options)](https://edge.bolerish.com/docs/react/use-surface/#use-surface) inside it and attach the returned ref to that element. Keep the component inside Edge.Provider. React 18 function components must forward the ref with `forwardRef`. For position changes, see [layout updates](https://edge.bolerish.com/docs/integration/#refresh-after-layout-changes). --- # React · Edge.Provider Creates a shared light for descendant surfaces. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/react/provider/ ## Edge.Styles Render once per SSR document, before application styles. React reuses this stylesheet when surfaces connect. Keep this component mounted while Edge is in use; use nonce when your CSP requires it. Without it or an explicit CSS import, the default CSS is added on the client when a surface connects. ```tsx ``` | Prop / option | Type | Default | Description | | --- | --- | --- | --- | | `nonce` | `string` | `undefined` | Optional request nonce for the style element. Use the same value on the server and during hydration. Required when your CSP permits inline style elements only with a nonce. | ## Edge.Provider Lets descendant Edge.Surface elements share one light without adding DOM elements. Each nested Edge.Provider creates an independent light. ```tsx {/* Your surfaces */} ``` | Prop / option | Type | Default | Description | | --- | --- | --- | --- | | `motion` | `'system' \| 'dynamic' \| 'static'` | `'system'` | System respects reduced-motion and device preferences. Dynamic follows mouse or pen input, even with reduced motion enabled. Static keeps a fixed direction. Touch updates the light position in viewport coordinates. Scrolling and lifting the finger preserve the last position; surfaces respond as they move beneath it. A new touch updates the position. Touch tracking follows the selected motion mode: static stays fixed, and system stays fixed when reduced motion is enabled. | | `staticDirection` | `number \| 'random'` | `315` | Direction in degrees for fixed lighting. Random chooses one shared direction per mount and keeps it across ordinary rerenders. Numbers must be finite. | | `direction` | `'toward' \| 'away'` | `'toward'` | toward faces highlights toward the pointer; away reverses them by 180 degrees. All surface styles preserve this choice. Only affects pointer-driven lighting; staticDirection controls fixed lighting. | | `range` | `number` | `480` | Distance over which dynamic lighting fades outside a surface, in viewport CSS pixels. Must be positive and finite. | | `intensity` | `number` | `0.75` | Shared light strength. Must be finite and between 0 and 1; invalid values throw a RangeError. | | `children` | `ReactNode` | `Required` | The area that shares this light. Ordinary children stay unchanged; only explicit surfaces respond. | | `ref` | `Ref` | `Unset` | Optional ref for the stable light handle. Call its refresh() method after position-only layout changes. | Pointer input comes from the document. The scope chooses which surfaces respond; it does not clip input to a wrapper rectangle. `staticDirection` applies whenever fixed lighting is active, including when `motion="system"` respects reduced motion. --- # React · Edge.Surface Applies lighting to a DOM element. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/react/surface/ ## Edge.Surface Renders one HTML element connected to the nearest provider. Native attributes and events follow the tag selected by `as`. ```tsx Your content ``` | Prop / option | Type | Default | Description | | --- | --- | --- | --- | | `pseudoElement` | `'after' \| 'before'` | `'after'` | Decoration slot. Choose before to preserve an existing ::after. If both slots are occupied, or the element is a native input, use a wrapper. Invalid values throw a RangeError. | | `edgeStyle` | `'raised' \| 'recessed' \| 'matte'` | `'raised'` | How the edge responds to light. All three styles preserve your component appearance. | | `color` | `string` | `currentColor` | Highlight color. Follows the element's text color by default. Accepts any CSS color string, including a CSS variable. | | `shadowColor` | `string` | `#0008` | Color on the opposite edge. Accepts any CSS color string; use transparent to remove this shadow on a light surface. | | `borderWidth` | `number` | `1` | Decorative edge thickness in pixels; it does not change the element's border. Negative values clamp to 0. Non-finite values use the default. | | `intensity` | `number` | `1` | Multiplier for the shared light strength. Finite values clamp to 0–1; non-finite values use the default. | | `as` | `HTML tag name` | `'div'` | The HTML element to render. Native attributes and the ref follow the chosen tag; custom React components are not accepted here. | | `children` | `ReactNode` | `Unset` | Content rendered inside the element. Use a wrapper for inputs and other elements that cannot display the decoration themselves. | | `ref` | `Ref` | `Unset` | Forwarded to the rendered element alongside the internal registration ref. React 19 callback-ref cleanup is preserved. | | `className` | `string` | `Unset` | Your classes, combined with the decoration classes. | | `style` | `CSSProperties` | `Unset` | Your inline styles, merged after the decoration bindings. Keep Edge-owned CSS variables intact unless deliberately overriding them. | Place every `Edge.Surface` inside a `Edge.Provider` owner; rendering it outside one throws an error. For native inputs and occupied pseudo-elements, see [Integration considerations](https://edge.bolerish.com/docs/integration/). Decoration aligns with the outside of the element's border. To connect an existing component’s HTML element, use [useSurface](https://edge.bolerish.com/docs/react/use-surface/#use-surface). --- # React · useLight Creates and configures a light handle. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/react/use-light/ ## useLight(options?) Returns a stable `Light` handle for explicit ownership without a provider. Pass it to `useSurface(light, options)`. Option changes update the existing light; use `Edge.Provider` for ordinary component trees. ```tsx function useLight(options?: LightOptions): Light; ``` | Prop / option | Type | Default | Description | | --- | --- | --- | --- | | `motion` | `'system' \| 'dynamic' \| 'static'` | `'system'` | System respects reduced-motion and device preferences. Dynamic follows mouse or pen input, even with reduced motion enabled. Static keeps a fixed direction. Touch updates the light position in viewport coordinates. Scrolling and lifting the finger preserve the last position; surfaces respond as they move beneath it. A new touch updates the position. Touch tracking follows the selected motion mode: static stays fixed, and system stays fixed when reduced motion is enabled. | | `staticDirection` | `number \| 'random'` | `315` | Direction in degrees for fixed lighting. Random chooses one shared direction per mount and keeps it across ordinary rerenders. Numbers must be finite. | | `direction` | `'toward' \| 'away'` | `'toward'` | toward faces highlights toward the pointer; away reverses them by 180 degrees. All surface styles preserve this choice. Only affects pointer-driven lighting; staticDirection controls fixed lighting. | | `range` | `number` | `480` | Distance over which dynamic lighting fades outside a surface, in viewport CSS pixels. Must be positive and finite. | | `intensity` | `number` | `0.75` | Shared light strength. Must be finite and between 0 and 1; invalid values throw a RangeError. | `range` affects dynamic lighting only. Fixed lighting uses `staticDirection` without distance attenuation. ## light.refresh() Remeasures surfaces on the next frame, even with a stationary pointer. Call after React commits changes to an element’s position or border thickness without a size notification. ```tsx interface Light { refresh(): void; } ``` Size changes and scrolling are handled automatically; see [layout updates](https://edge.bolerish.com/docs/integration/#refresh-after-layout-changes) for details. --- # React · useSurface Returns a ref that connects an existing DOM element to a light. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/react/use-surface/ ## useSurface(options?) Returns a callback ref that connects an existing HTML element to the nearest provider. Attach it to the element displaying the border and keep your existing `className` and `style`. ```tsx const ref = useSurface(options); ``` ```tsx function Area() { return ; } function ExistingCard() { const ref = useSurface(); return Your existing component; } ``` In React 18, an existing function component must use `forwardRef` to pass the ref to its HTML element. React 19 also supports receiving ref as a prop. Without an explicit light, this hook requires an Edge.Provider. For advanced ownership, use `useSurface(light, options)` with a handle returned by `useLight`. The explicit light takes precedence over the provider. | Prop / option | Type | Default | Description | | --- | --- | --- | --- | | `pseudoElement` | `'after' \| 'before'` | `'after'` | Decoration slot. Choose before to preserve an existing ::after. If both slots are occupied, or the element is a native input, use a wrapper. Invalid values throw a RangeError. | | `edgeStyle` | `'raised' \| 'recessed' \| 'matte'` | `'raised'` | How the edge responds to light. All three styles preserve your component appearance. | | `color` | `string` | `currentColor` | Highlight color. Follows the element's text color by default. Accepts any CSS color string, including a CSS variable. | | `shadowColor` | `string` | `#0008` | Color on the opposite edge. Accepts any CSS color string; use transparent to remove this shadow on a light surface. | | `borderWidth` | `number` | `1` | Decorative edge thickness in pixels; it does not change the element's border. Negative values clamp to 0. Non-finite values use the default. | | `intensity` | `number` | `1` | Multiplier for the shared light strength. Finite values clamp to 0–1; non-finite values use the default. | A DOM element can connect to only one light. Do not attach the ref to a parent element with different dimensions. Options update without replacing the element. Hook decoration attaches after hydration; use `Edge.Surface` to include appearance classes and variables in server output. --- # Styles · Style Choose how a surface responds to light without changing its base styles. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/styles/ ## Compare the edge response Choose a style and move your pointer around the card. The selection also updates this site’s cards, code blocks and navigation surfaces. Compare edge styles ```tsx const light = useLight(); const surface = useSurface(light, { edgeStyle: "raised" }); Your component ``` ## Style values | Value | Behavior | | --- | --- | | `raised` | Highlights the edge facing the light. Default. | | `recessed` | Draws the highlight one decorative edge thickness inward. Preserves the selected light direction. | | `matte` | Softens the edge response. | For additional settings, see the [API reference](https://edge.bolerish.com/docs/react/surface/#lighting-surface). ## Raised Use `edgeStyle: 'raised'` for an outward-facing edge highlight. ## Recessed Use `edgeStyle: 'recessed'` for a highlight inset by one decorative edge thickness, such as on input wrappers. It preserves the selected light direction. ## Matte Use `edgeStyle: 'matte'` for a softer, quieter border. ## Customize the highlight Each surface uses its own text color, even when nested, and follows its element's border radius. Set `color` to override the highlight, or `intensity` to multiply the shared light strength. Use `shadowColor="transparent"` to remove the opposite-edge shadow. `borderWidth` changes the decoration thickness in pixels, not the element's border. Pass options to [Edge.Surface](https://edge.bolerish.com/docs/react/surface/#lighting-surface); no CSS variable declarations are needed. The effect approximates a direction on axis-aligned rectangles, not a physical point light. Near the center, directional intensity fades over a region proportional to the surface size. For existing decorations and input wrappers, see [Integration considerations](https://edge.bolerish.com/docs/integration/). --- # Styles · Motion Choose whether a shared light follows the pointer or keeps a fixed direction. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/motion/ ## Choose motion behavior Use `system` to respect reduced motion. Touch updates the light position in viewport coordinates. Scrolling and lifting the finger preserve the last position; surfaces respond as they move beneath it. A new touch updates the position. Offer `dynamic` only as an explicit choice because it overrides reduced motion. See [Motion](https://edge.bolerish.com/docs/motion/) for details. ## Choose motion behavior Try each mode below. The selection updates the shared light across this site, including the example card. Compare motion ```tsx const light = useLight({ motion: "dynamic" }); const surface = useSurface(light, { edgeStyle: "raised" }); Your component ``` ## Pointer lighting toward lights the edge facing the pointer; away lights the opposite edge. range is the fade distance outside each surface. For example, range: 40 fades to zero when the pointer is 40 CSS pixels outside the card; it does not create a 40-pixel bright circle around the pointer. Move the pointer outside the card to compare values. Fixed lighting ignores these settings. Pointer lighting ```tsx const light = useLight({ motion: 'dynamic', direction: "toward", range: 480 }); ``` ## Motion values | Value | Behavior | | --- | --- | | `system` | Respects reduced motion and input preferences. Library default. | | `dynamic` | Follows mouse, pen or touch contact, including with reduced motion enabled. | | `static` | Keeps a fixed direction; ignores pointer movement. | For additional settings, see the [API reference](https://edge.bolerish.com/docs/react/provider/#lighting). ## System Without a precise hover device, lighting starts fixed. Mouse or pen input can enable tracking when reduced motion is off. Touch updates the light position in viewport coordinates. Scrolling and lifting the finger preserve the last position; surfaces respond as they move beneath it. A new touch updates the position. ## Dynamic Offer this mode as an explicit choice because it overrides reduced motion. The effect stays hidden until mouse, pen or touch contact arrives. ## Static Set `staticDirection` to any finite angle in degrees or `"random"`. The demo offers 0°, 90°, 180°, 270° and 315°. Random chooses one shared direction per mount; rerenders and appearance changes preserve it. Remount to choose a new direction. Static ```tsx const light = useLight({ motion: 'static', staticDirection: "random" }); ``` ## Respect user preferences Keep focus, selection and validation visible independently of lighting. See [Accessibility](https://edge.bolerish.com/docs/integration/#preserve-native-interactions) for input and forced-colors behavior. --- # Guides · Integration considerations Handle decoration conflicts, native inputs and layout changes. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/integration/ ## Choose motion behavior System respects reduced-motion and device preferences. Dynamic follows mouse or pen input, even with reduced motion enabled. Static keeps a fixed direction. Touch updates the light position in viewport coordinates. Scrolling and lifting the finger preserve the last position; surfaces respond as they move beneath it. A new touch updates the position. Touch tracking follows the selected motion mode: static stays fixed, and system stays fixed when reduced motion is enabled. ## Understand rendering cost Each light queues at most one frame, reads geometry before writing styles, and skips unchanged output. Gradient changes still require browser rendering work; this does not guarantee a frame rate or battery cost. ## Preserve native interactions Keep labels, text contrast, base borders and visible keyboard focus. Decoration does not capture pointer events; input values, selection, keyboard handling and portals remain under your control. Forced-colors mode hides decoration. Communicate selection, validation and availability independently of the highlight. ## Keep existing decorations Edge uses `::after` by default. Set `pseudoElement: 'before'` to keep an existing `::after`. If both pseudo-elements are occupied, decorate a wrapper. Keep existing pseudo-elements ```tsx import { Edge } from '@bolerish/edge'; Your existing ::after stays intact. ``` ## Wrap native inputs Native inputs do not reliably display pseudo-element decoration. Connect a surrounding `label` or `div` with a matching radius instead. Keep the input’s label, focus, validation and keyboard behavior. Use `recessed` for an inset appearance. ## Refresh after layout changes Size changes, nested scrolling, viewport resizing, font loading and resource loads update geometry automatically. After a position-only change or a element's border-thickness change without a size notification, call `light.refresh()` once the new layout is applied. It updates even with a stationary pointer. See [light.refresh()](https://edge.bolerish.com/docs/react/use-light/#refresh) for the React call. ## Geometry and document boundaries Edge approximates axis-aligned rectangles. Rotation, perspective transforms and cross-document portals are unsupported. Portals within the same document can share a light. For focus, selection and validation, see [Accessibility](https://edge.bolerish.com/docs/integration/#preserve-native-interactions). --- # Guides · AI Integration Give your assistant current Edge documentation before it changes your UI. Package: @bolerish/edge 0.4.0 Source: https://edge.bolerish.com/docs/ai-integration/ ## Read the documentation Start with [llms.txt](https://edge.bolerish.com/llms.txt) for a short index linking to Markdown versions of each guide and API reference. Use [llms-full.txt](https://edge.bolerish.com/llms-full.txt) when your assistant needs all the documentation in one file. These files are generated from the same content as this site and identify the package version they describe. Publishing them does not guarantee that an assistant reads them automatically; include the URL in your request. ## Write a prompt Paste the component you want to update and describe which elements should respond to the light. For example: ```text Read https://edge.bolerish.com/llms.txt and follow the relevant Markdown links. Check the installed @bolerish/edge version and its types before choosing APIs. Add Edge to the component below, preserving its markup, colors and interactions. Connect only the surfaces I specify. Keep native controls and focus indicators. Use the library's default motion="system" unless I ask for another mode. ``` ## Match the installed version Check your package manifest or lockfile. Web documentation may describe a newer release; if versions differ, use the installed package’s declarations and matching documentation. Do not upgrade dependencies just to match an example.